Skip to main content

Message Exchange for Social Care and Health (MESH) API

The Message Exchange for Social Care and Health (MESH) is the main secure large file transfer service used across health and social care organisations.

Overview

Use this API to securely transfer healthcare data between organisations using the Message Exchange for Social Care and Health (MESH), which is a component of Spine.

You can interact with MESH via a virtual mailbox, only accessible by your organisation. Incoming messages appear in the inbox section of the mailbox. To send a message, place it in the outbox section of your mailbox. Outgoing messages are tagged with the receiving organisation's mailboxID. Spine then delivers the message to the receiving organisation's mailbox inbox. In addition to the sender and receiver mailboxID's you must also include a workflowID label in each message. MESH provides all the workflowID codes, as they identify what type of data the message contains. This helps the receiving organisation process the data after they receive it (For example, the receiver may process X-ray images very differently from blood test results). There is a Java based MESH client you can use to access MESH, which calls the RESTful MESH API under the hood. If you want a more tightly knitted interface with MESH you can also call the MESH API directly in your applications.

This guide documents the MESH API endpoints and describes how they should be used.

This API can only be used where there is a legal basis to do so. You should make an access request before you go too far with your development.

You must have made this request before you can go live (see 'Onboarding' below).

Prerequisites

You must register with MESH to use the API. As part your registration, we will provide you with these items:

  • MESH mailbox (with a unique ID and password)
  • client Transport Layer Security (TLS) certificates
  • environment shared secret
  • list of workflow IDs to identify types of messages your organisation will send and receive

None.

API Status and Roadmap

This API is currently live.

To see our roadmap, or to suggest, comment or vote on features for this API, see our interactive product backlog.

Technology

This API is RESTful.

Network access

This API is available on the internet and, indirectly, on the Health and Social Care Network (HSCN).

To use this API with NHS smartcards (see below) you do need a HSCN connection, although internet facing alternatives are available.

For more details see Network access for APIs.

Environments and Testing

There are several independent, externally accessible instances of MESH for use by parties external to NHS Digital for testing, each with a different root URL.

Some environments require a connection to the HSCN network.

Purpose URL HSCN required
Development https://msg.dev.spine2.ncrs.nhs.uk/ Yes
Integration https://msg.int.spine2.ncrs.nhs.uk/ Yes
Integration https://msg.intspineservices.nhs.uk/ No
Deployment https://msg.dep.spine2.ncrs.nhs.uk/ Yes
Production https://mesh-sync.national.ncrs.nhs.uk/ Yes
Production https://mesh-sync.spineservices.nhs.uk No

Note - each environment has the same shared secret but requires different client TLS certificates.

Develop against a local MESH sandbox server

Here is an existing (unsupported) example of a RESTful interface on Github. This python client also contains a mock MESH server which you can run locally without any real MESH credentials.

With the example RESTful mesh client installed, you can run the mock server with;

python3 -m mesh_client.mock_server

The client TLS certificates which you need to connect to the mock server are in the python library. You can either copy them from the python library directory to your working directory, or download them from here:

  • client.cert.pem
  • client.key.pem
  • ca.cert.pem

With the certificates in place, getting the URL should result in a Not Found error. Without the certificates, you will get a TLS error.

curl -k \ 
  --cacert 'ca.cert.pem' \
  --key 'client.key.pem' \
  --cert 'client.cert.pem' \
  'https://localhost:8000/'

MESH Authorization header

The MESH API requests require an authentication token in the HTTP Authorization Header. To be valid, the authorization tokens must match the schema described below. The token includes cryptographic hashes of your organisation's MESH mailbox password and the environment-wide shared secret. As an additional security measure each token which matches the schema is valid for one request only, so a new token must be generated for every request. Any repeated use of a token will result in a 403: Not Authorized response from the MESH server.

The Authorization token is made up of six elements. With the exception of the first and second elements, each element is separated from the next by a colon, :.

Name Description
NHSMESH The name of the Custom Authentication Schema. The Authentication Header should prefix the generated authentication token. The space at the end of the schema is important
mailbox_id ID of the Mailbox sending the HTTP Request, must be uppercase
nonce A GUID used as an encryption Nonce
nonce_count The number of times that the same Nonce has been used
timestamp The current date and time in yyyyMMddHHmm format
hash HMAC-SHA256 hash see the list below

The hash is compiled of the following items:

  • The key is the MESH environment shared secret
  • The message is the concatenation of the 5 following elements, joined by ':'
    • mailbox_id - same as element 2
    • nonce - same as element 3
    • nonce_count - same as element 4
    • mailbox_password - The password for the MESH Mailbox
    • timestamp - same as element 5

Changing the nonce and/or nonce_count elements between requests ensures the Authorization header is unique and valid.

Notes

  • the server will reject the request if the timestamp supplied is not within 2 hours of the server time
  • in the example below HMACSECRETKEY has been [REDACTED], this is the 'environment shared secret' which you received as part of creating your mailbox

Example implementation

Here is an implementation of the above in python3.

""" Python code to generate a valid authorization header. """
import hmac
import uuid
import datetime from hashlib
import sha256

AUTHSCHEMANAME = "NHSMESH " # Note: Space at the end of the schema.
HMACSECRETKEY = "[REDACTED]" # Note: Don't hard code your passwords in a real implementation.

def buildmeshauthorizationheader(mailboxid: str, password: str = "password", nonce: str = None, noncecount: int = 0):
  """ Generate MESH Authorization header for mailboxid. """
  #Generate a GUID if required.
  if not nonce:
    nonce = str(uuid.uuid4())
  #Current time formatted as yyyyMMddHHmm
  #for example, 4th May 2020 13:05 would be 202005041305
  timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M")
  
  #for example, NHSMESH AMP01HC001:bd0e2bd5-218e-41d0-83a9-73fdec414803:0:202005041305
  hmac_msg = mailbox_id + ":" + nonce + ":" + str(nonce_count) + ":" + password + ":" + timestamp
  
  #HMAC is a standard crypto hash method built in the python standard library.
  hash_code = hmac.HMAC(HMAC_SECRET_KEY.encode(), hmac_msg.encode(), sha256).hexdigest()
  return (
    AUTH_SCHEMA_NAME # Note: No colon between 1st and 2nd elements.
    + mailbox_id + ":"
    + nonce + ":"
    + str(nonce_count) + ":"
    + timestamp+ ":"
    + hash_code
)

MESH API pseudocode

Here is the flow of API calls you should make to use MESH effectively:

  • inbox poll cycle
  • outbox workflow

The mailbox should be validated once every 24 hours using the Validate a mailbox endpoint.

Inbox poll cycle

Spine gives each message a unique messageID after you post it to your outbox. It is the primary identifier for the message during MESH transit.

You should poll mailboxes at most every 5 minutes, but at least every 24 hours. The pseudo code for a mailbox's poll is:

  1. Poll to get the messageIds messages ready to download from the Inbox endpoint.
  2. For messageID from step 1, you should:
    • download the message from the Download message endpoint
    • if identified as a chunked message, download all remaining chunks from the Download message chunk endpoint
    • acknowledge receipt of the message via the Acknowledge message endpoint
  3. Repeat step 2 until you have processed the number of messages returned in step 1.
  4. If you received exactly 500 messages in step 1 then repeat from step 1 immediately polling again and download, until you receive 0 messages in step 1.

Asynchronous error reporting

Most problems with message transfer are indicated synchronously (that is immediately) when the 'Send Message' endpoint is called. However, it is possible that some errors may occur after a successful request (that is, asynchronously). Such asynchronous errors are reported to the sending organisation as messages in their inbox to be accessed as part of the inbox poll cycle. Error reports differ from regular messages in these ways:

  • the Download message endpoint will have a different value for the Mex-Messagetype header
    • DATA for a regular organisation-to-organisation message
    • REPORT for an error report
  • the Download message response body of an error report message is empty

We strongly recommend that you check the value of Mex-Messagetype after downloading each message so that you can take appropriate follow up action if needed.

Error Report Header Description
Mex-Statusevent Step in the MESH server side process when the error occurred
Mex-Linkedmsgid The messageId of the undelivered message
Mex-Workflowid The workflowId of the undelivered message
Mex-Statustimestamp Time the error occurred
Mex-Localid Sender assigned localId of the unacknowledged message
Mex-Statuscode Indicate the status of the message, non-00 indicates error
Mex-Messageid The messageId of the error report (not the undelivered message)
Mex-Statussuccess SUCCESS or ERROR (will always be ERROR in an error report)
Mex-Statusdescription Indicate the status the message, non-00 indicates error
Mex-To Intended receiver of the undelivered message
Mex-Messagetype REPORT
Mex-Subject The subject of the undelivered message

Error codes

Some of the below errors are only applicable for some API calls. For example, error code 15 would only be found when calling 'Child Protection Information Services' (CP-IS).

Error code Typical description
02 Data file is missing or inaccessible
06 Malformed headers
07 Invalid From Address, the mailbox does not match the authorization header
08 Missing Mex-To header
11 Invalid Message Type for the transfer, should be DATA
12 Unregistered to address
14 Undelivered message
15 Bad 'Child Protection - Information Sharing' (CP-IS) File
16 Sender is not allowed to send messages of this type
17 Receiver not registered for workflowId
19 workflowId does not support chunked files

Outbox Workflow

The maximum amount of data allowed by MESH in a single request message is 100MB (20MB over Internet, 100MB over HSCN). The MESH API allows larger messages to be sent by breaking the message into "chunks" that are transmitted as a single message over multiple requests. The upper limit of a single chunked message is 20GB.

The MESH UI and older versions of the MESH client do not support chunking. It is prudent to ensure that the receiver's interface to MESH for your workflowId handles chunked messages prior to sending. To do this:

  1. Determine the size of your message data (after compression) with a standard algorithm (such as gzip). If the compressed message is larger than 100MB, smaller than 20GB, and the receiving mailbox / workflowId supports chunking, then you can send a chunked message. To prepare for this:
    • split the uncompressed data into ordered chunks
    • independently compress each chunk with the same compression algorithm (such as gzip) such that each chunk is smaller than 100MB
    • use the first chunk (after compression) as the initial message data
  2. Send a message with appropriate workflowId, receiver & mailboxId. To do this:
    • optionally include localId from step 2 for tracking. This field must not contain PID.
    • if sending a chunked message, include an extra header to indicate that this is the first in a series of chunks, then submit the subsequent chunks via the 'Send Chunked Message' endpoint
  3. A messageID will be returned which is the unique identifer and can be used for tracking and helping with incident resolution. It would be good practice to log this identifier.

Message expiration

Messages that are not downloaded and acknowledged within five days of delivery are removed from your inbox. The sending organisation receives an error report explaining that the receiver did not collect the message. Uncollected messages are completely deleted from the MESH server 30 days after the initial delivery. If the sending organisation cannot re-send the message within the intervening time, it may contact the NHS Digital national service desk with the error report details and ask for the message to be placed in your inbox again.

Onboarding

You need to get your software approved by us before it can go live with this API. We call this onboarding. The onboarding process can sometimes be quite long, so it's worth planning well ahead.

Information

'Try this now' feature on the below endpoints are currently unavailable and awaiting removal.

Endpoints: Endpoints

Acknowledge message

put
/messageexchange/{mailboxID}/inbox/{messageID}/status/acknowledged

Overview

Use this endpoint to acknowledge the successful download of a message. This operation:

  • closes the message transaction on Spine
  • removes the message from your mailbox inbox (which means that the messageId will not appear in subsequent calls to the Check Inbox endpoint and cannot be downloaded again)

If you fail to acknowledge a message after five days in the inbox this will result in a non delivery report to the senders inbox.

Request
      curl -k \
      --request 'PUT' \
      --cacert 'mesh-ca.pem' \
      --key 'mesh-client-key.pem' \
      --cert 'mesh-client-cert.pem' \
      --header 'Authorization: NHSMESH X26HC005:bb59be38-e50b-4e5a-9f11-e566e7509552:0:202006041718:8c415905280304918033bcab054909e4582e5fdf544eb18a9dd7366fb868bcf3' \
      https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox/\
      20200529155357895317_3573F8/status/acknowledged
Response
  { "messageId" : "20200529155357895317_3573F8" }

Request

Path parameters
Name Description
messageID
String
The ID of the message
Required
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
messageID
string
Example: 20200529155357895317_3573F8
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status

Check an inbox

get
/messageexchange/{mailboxID}/inbox

Overview

Use this endpoint to return the messageId of messages in the mailbox inbox ready for download. Client systems MUST poll their assigned inbox a minimum of once a day and a maximum of once every five minutes for messages (unless there are more messages waiting to download).

A maximum of 500 messageId are returned in every request. The polling/download cycle should immediately continue until the mailbox has been drained and less than 500 messages have been received in the response.

Request
  curl -k \
  --request 'GET' \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:66eef28b-e097-421d-998d-ea0c92c2c2fb:0:202006041718:60e25fb4c6b400d7e3dfa901b68715b2fda4cfbcd27b8bff3d21dbaae06a65d5' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox
Response
 {"messages": []}

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
messages
array
Array of strings of messageId in inbox
string
HTTP status: 400
Bad Request
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status

Check an inbox's count

get
/messageexchange/{mailboxID}/count

Overview

Use this endpoint to check the number of messages currently held in the MESH mailbox that are ready to download.

This endpoint has been deprecated as it does not need to be called as part of the polling cycle.

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
count
integer
number of messages in mailbox
internalID
string
Internal reference for diagnosis of errors
Example: 20200603094542820500_AEA7BA_1573484974
allResultsIncluded
boolean
In rare cases not all results can be included, if false the mailbox needs to download.
HTTP status: 400
Bad Request
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status

Download message

get
/messageexchange/{Recipient}/inbox/{messageID}

Overview

Use this endpoint to retrieve a message based on the messageid obtained from the 'Check Inbox' endpoint.

Message expiration

Messages that are not downloaded and acknowledged within five days of delivery are removed from your inbox. The sending organisation receives an error report explaining that the receiver did not collect the message. Uncollected messages are completely deleted from the MESH server 30 days after the initial delivery. If the sending organisation cannot re-send the message within the intervening time, it may contact the NHS Digital national service desk with the error report details and ask for the message to be placed in your inbox again.

Report Messages

The Mex-Messagetype header will indicate if the payload is a DATA message or a REPORT.
Error reports differ from regular messages in these ways:

  • the Download message endpoint will have a different value for the Mex-Messagetype header
    • DATA for a regular organisation-to-organisation message
    • REPORT for an error report
  • the Download message response body of an error report message is empty
Request
  curl -k \
  --request 'GET' \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:2942264f-46e5-450f-90fc-22a0c09efa37:0:202006041718:bba1c9550e6ce5f2fff2c98712b27c4bf7f8b8bf9dfda3f52e27e6db71dd8f9d' \
  https://msg.int.spine2.ncrs.nhs.uk/messageexchange/recipient/inbox/messageID
Response
  {"messages": ["20200529155357895317_3573F8"]}

Request

Path parameters
Name Description
messageID
String
The ID of the message
Required
Recipient
String
Recipient mailbox ID
Example: {Recipient Mailbox ID}
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 206
Partial download – Indicates that chunk has been downloaded successfully and that there are further chunks.
Body
Content type: binary
Schema
Name Description
object
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status
HTTP status: 410
Gone, message has already been downloaded and acknowledged
Body
Content type: application/json
Schema
Name Description
object

Download message chunk

get
/messageexchange/{Recipient}/inbox/{messageID}/{chunkNo}

Overview

Use this endpoint to download a chunked message. The initial step is to call the 'Download Message' endpoint with the messageId given by the 'Check Inbox' endpoint as usual. When the message is chunked, the load message endpoint response differs in two ways:

  • the response code is '206: Partial Content' (instead of '200: OK')
  • the response headers contain Mex-Chunk-Range: 1:n

This endpoint is used to download the remaining n-1 chunks.

Request

Following on from the example in the Send chunked message endpoint, Alice checks her inbox and sees a new message.

  curl -k \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --request 'GET' \
  --header 'Authorization: NHSMESH X26HC005:142b8a1e-e953-4e5e-98a8-b27741e15747:0:202006041718:0ab046e6c9ed7ed0e47eef3e04725846047d7ee3e71e868c84ffda32e24926f4' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox

She downloads the first part of the message. Note this use of curl uses the --include argument, to show the value of the HTTP headers in the MESH response.

  curl -k \
  --include \
  --request 'GET' \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:777670ce-02f7-44fe-a53b-eb33eb1cb564:0:202006041718:8d22e541bbfd55baeccb6e088704320c75ea150fc8fa7dc137121cbdf939a7bb' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox/\
  20200601122152994285_D59900 | tr -d '\r'
  HTTP/1.1 206 Partial Content
  Server: nginx
  Date: Mon, 01 Jun 2020 12:24:09 GMT
  Content-Type: application/octet-stream
  Content-Length: 100
  Connection: keep-alive
  Mex-Chunk-Range: 1:2
  Mex-Workflowid: API-DOCS-TEST
  Mex-Content-Compressed: N
  Mex-Addresstype: ALL
  Mex-Statussuccess: SUCCESS
  Mex-Statusdescription: Transferred to recipient mailbox
  Mex-Messagetype: DATA
  Mex-Statusevent: TRANSFER
  Mex-Tosmtp: x26hc005@dts.nhs.uk
  Mex-Version: 1.0
  Mex-Fromsmtp: x26hc006@dts.nhs.uk
  Mex-To: X26HC005
  Mex-Statustimestamp: 20200601122152
  Mex-Localid: api-docs-bob-sends-alice-a-chunked-file
  Mex-Statuscode: 00
  Mex-Filename: message.txt.gz
  Mex-Messageid: 20200601122152994285_D59900
  Mex-From: X26HC006

  Hi Alice,

  This is Bob. It's really nice that we can communicate via SPINE!

  I hope to hear more fro

Here we have added the --include argument to curl which prints more response information, including the HTTP response code and response headers. (tr -d '\r' invokes a linux utility to strip carriage returns from the end of each of the lines added to the curl --include argument).

Alice notes that the response code is 206 Partial Content - meaning it is the first part of a chunked message. How much of the message remains is given by the Mex-Chunk-Range header, 1:2 indicating the response body is the first of two parts.

Alice makes another call to retrieve the second part of the message.

  curl -k \
  --include \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:71139532-9215-4ff8-8a74-d602386bac30:0:202006041718:a23d903df6b10388e9c0b12d651ce3cc0e2016006dc72e2f9671f596c9bb70c4' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox/\
  20200601122152994285_D59900/2 | tr -d '\r'
  HTTP/1.1 200 OK
  Server: nginx
  Date: Mon, 01 Jun 2020 12:24:17 GMT
  Content-Type: application/octet-stream
  Content-Length: 27
  Connection: keep-alive
  Mex-Content-Compressed: N
  Mex-Addresstype: ALL
  Mex-Localid: api-docs-bob-sends-alice-a-chunked-file
  Mex-Tosmtp: x26hc005@dts.nhs.uk
  Mex-Chunk-Range: 2:2
  Etag: "866243ab74e0107a4d5835f8d6552e7f20c39ee1"
  Mex-Filename: message.txt.gz
  Mex-Version: 1.0
  Mex-Fromsmtp: x26hc006@dts.nhs.uk
  Mex-Workflowid: API-DOCS-TEST
  Mex-To: X26HC005
  Mex-Messagetype: DATA
  Mex-Messageid: 20200601122152994285_D59900
  Mex-From: X26HC006

  m you in the future,

  Bob.

That this is the final part of the message is indicated in two ways:

  • the response code is 200 OK rather than 206 Partial Content
  • the Mex-Chunk-Range response header is 2:2

Request

Path parameters
Name Description
Recipient
String
Recipient mailbox ID
Example: {Recipient Mailbox ID}
Required
messageID
String
The ID of the message
Required
chunkNo
Integer
The index number of the chunk
Example: 1
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 206
Partial download – Indicates that chunk has been downloaded successfully and that there are further chunks.
Body
Content type: binary
Schema
Name Description
object
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status
HTTP status: 404
Message does not exist
Body
Content type: application/json
Schema
Name Description
object

MESH address lookup

get
/endpointlookup/mesh/{odsCode}/{Mex-workflowid}

Overview

Use this endpoint to search for the mailbox of the organisation you will be sending data to, using their unique Organisation Data Service (ODS) code, their MESH mailboxID and the agreed workflowID for the data.

An example call:

Request
curl -k \
--cacert 'mesh-ca.pem' \
--key 'mesh-client-key.pem' \
--cert 'mesh-client-cert.pem' \
--header 'Authorization: NHSMESH X26HC005:a5d25a21-57c3-40d1-8794-bea42e82039b:0:202006041718:725665f0956b73c5f9ec5e0e0d413046fc0729e3b893864b6d5f672dda2bfd13' \
https://mesh-sync.spineservices.nhs.uk/endpointlookup/mesh/SCREEN2/SPINE_GPCAPITATION_EXTRACT
Response
{
  "query_id": "20200601131040203367_A441C2_1573484974",
  "results": [
    {
      "endpoint_type": "MESH",
      "description": "Breast Cancer Screening Services",
      "address": "X26HC022"
    },
    {
      "endpoint_type": "MESH",
      "description": "AAA Screening Services",
      "address": "X26HC021"
    },
    { 
    "endpoint_type": "MESH",
      "description": "Bowel Cancer Screening Services (England, DMS)",
      "address": "X26HC020"
    }
  ]
}

Note: neither the ods-code nor workflowId in this example are real.

Request

Path parameters
Name Description
odsCode
String
All health and social care organisations have a unique ODS code
Example: SCREEN2
Required
Mex-workflowid
String
Workflow ID
Example: {Workflow ID}
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
query_id
string
Example: 20200601131040203367_A441C2_1573484974
results
array
string
HTTP status: 403
Message does not exist
Body
Content type: application/json
Schema
Name Description
object

Outbox tracking

get
/messageexchange/{mailboxID}/outbox/tracking

Overview

Use this endpoint to inquire about the status of messages sent from your outbox. When determining the frequency of the calling of this endpoint consider that MESH is asynchronous and it may be sometime (hours) until the recipient downloads. This endpoint must not be frequently polled.

The messageId is the value returned in the response to a message upload.

This endpoint must not be used to replace a business ack message. If the business process requires confirmation that the recipient has processed the message then a business ACK should be sent over MESH (convention is the same workflow is used appended with _ACK).

Request

It is possible for Bob to check the status of the chunked message he sent to Alice. (Note that in this example, Alice has not acknowledged the chunked message she received from Bob).

  curl -k \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC006:1f6c9442-eb9a-440c-b4ed-ee4fd525e176:0:202006041718:c2d92e6abd637e664fd8bdbf1d753c7d42a16ee2bc317f62a654ef649a9956d7' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox/tracking?messageID=20210311101813838554_1B8F53
Response
  {
    "processId": null,
    "addressType": "ALL",
    "localId": "api-docs-bob-sends-alice-a-chunked-file",
    "recipientBillingEntity": "England",
    "dtsId": "20210311101813838554_1B8F53",
    "statusSuccess": null,
    "messageType": "DATA",
    "statusTimestamp": null,
    "senderBillingEntity": "England",
    "senderOdsCode": "X26",
    "partnerId": null,
    "recipientName": "APIM bebop",
    "senderName": "APIM bebop",
    "subject": null,
    "statusEvent": null,
    "version": "1.0",
    "encryptedFlag": null,
    "statusDescription": null,
    "senderOrgName": "TEST Org Partnership Trust",
    "status": "Accepted",
    "workflowId": "API-DOCS-TEST",
    "senderOrgCode": "TestOrg",
    "recipientOrgName": "TEST Org Partnership Trust",
    "expiryTime": "20200606122153",
    "senderSmtp": "x26hc006@dts.nhs.uk",
    "fileName": "message.txt.gz",
    "recipientSmtp": "x26hc005@dts.nhs.uk",
    "meshRecipientOdsCode": "X26",
    "compressFlag": null,
    "uploadTimestamp": "20200601122152",
    "recipient": "X26HC005",
    "contentsBase64": true,
    "sender": "X26HC006",
    "checksum": null,
    "isCompressed": null,
    "contentEncoding": "gzip",
    "recipientOrgCode": "TestOrg",
    "messageId": "20210311101813838554_1B8F53",
  "statusCode": null,
    "fileSize": 187
  }

Suppose Alice only now acknowledges the message Bob sent.

Request
  curl -k \
  --request 'PUT' \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:57db9dd2-2156-4c02-90d4-66e7082179db:0:202006041718:aae81ea5fc3757a6218df2a6dc9991d447dbd406dba15e1ca67540f9411e7388' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005/inbox/\
  20210311101813838554_1B8F53/status/acknowledged
Response
  {"messageId" : "20210311101813838554_1B8F53" }

The next call to Outbox tracking by Bob

Request
  curl -k \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC006:dd3f8609-b2c3-4f5a-aa62-c456579b8f77:0:202006041718:9d5dc80e4ac8d89c1ce0e8feaa1e14b2c3ab9ee3ccc95f3f8483086e2ed40bd8' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox/tracking?messageID=20210311101813838554_1B8F53
Response
  {
    "downloadTimestamp": "20200601122957",
    "status": "Acknowledged",
    "messageId": "20210311101813838554_1B8F53"
  }

This shows the status field of the response has changed from Accepted to Acknowledged. All of the fields in the previous response are also included.

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Query parameters
Name Description
messageID
String
Value of messageID returned in the send message response
Example: 20210311101813838554_1B8F53
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
processId
string
addressType
string
Example: ALL
localId
string
Example: api-docs-bob-sends-alice-a-chunked-file
recipientBillingEntity
string
Example: England
dtsId
string
Example: 20210311101813838554_1B8F53
statusSuccess
string
messageType
string
Example: DATA
statusTimestamp
string
senderBillingEntity
string
Example: England
senderOdsCode
string
Example: X26
partnerId
string
recipientName
string
Example: APIM bebop
senderName
string
Example: APIM bebop
subject
string
statusEvent
string
version
string
Example: 1.0
encryptedFlag
string
statusDescription
string
senderOrgName
string
Example: TEST Org Partnership Trust
status
string
Example: Accepted
workflowId
string
Example: API-DOCS-TEST
senderOrgCode
string
Example: TestOrg
recipientOrgName
string
Example: TEST Org Partnership Trust
expiryTime
string
Example: 20200606122153
senderSmtp
string
Example: x26hc006@dts.nhs.uk
fileName
string
Example: message.txt.gz
recipientSmtp
string
Example: x26hc005@dts.nhs.uk
meshRecipientOdsCode
string
Example: X26
compressFlag
string
uploadTimestamp
string
Example: 20200601122152
recipient
string
Example: X26HC005
sender
string
Example: X26HC006
checksum
string
isCompressed
string
contentEncoding
string
Example: gzip
recipientOrgCode
string
Example: TestOrg
messageId
string
Example: 20210311101813838554_1B8F53
statusCode
string
fileSize
integer
Example: 187
HTTP status: 403
Message does not exist
Body
Content type: application/json
Schema
Name Description
object

Outbox tracking

get
/messageexchange/{mailboxID}/outbox/tracking/{localID}

Overview

This endpoint is now deprecated tracking?messageID should be used instead.

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
localID
String
Value of Mex-LocalID provided by sender
Example: api-docs-bob-sends-alice-a-chunked-file
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
processId
string
addressType
string
Example: ALL
localId
string
Example: api-docs-bob-sends-alice-a-chunked-file
recipientBillingEntity
string
Example: England
dtsId
string
Example: 20200601122152994285_D59900
statusSuccess
string
messageType
string
Example: DATA
statusTimestamp
string
senderBillingEntity
string
Example: England
senderOdsCode
string
Example: X26
partnerId
string
recipientName
string
Example: APIM bebop
senderName
string
Example: APIM bebop
subject
string
statusEvent
string
version
string
Example: 1.0
encryptedFlag
string
statusDescription
string
senderOrgName
string
Example: TEST Org Partnership Trust
status
string
Example: Accepted
workflowId
string
Example: API-DOCS-TEST
senderOrgCode
string
Example: TestOrg
recipientOrgName
string
Example: TEST Org Partnership Trust
expiryTime
string
Example: 20200606122153
senderSmtp
string
Example: x26hc006@dts.nhs.uk
fileName
string
Example: message.txt.gz
recipientSmtp
string
Example: x26hc005@dts.nhs.uk
meshRecipientOdsCode
string
Example: X26
compressFlag
string
uploadTimestamp
string
Example: 20200601122152
recipient
string
Example: X26HC005
sender
string
Example: X26HC006
checksum
string
isCompressed
string
contentEncoding
string
Example: gzip
recipientOrgCode
string
Example: TestOrg
messageId
string
Example: 20200601122152994285_D59900
statusCode
string
fileSize
integer
Example: 187
HTTP status: 300
Multiple options (The localId provided with the message was not unique)
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 403
Message does not exist
Body
Content type: application/json
Schema
Name Description
object

Send chunked message

post
/messageexchange/{mailboxID}/outbox/{messageID}/{chunkNo}

Overview

Use this endpoint to send a chunked message. The 'Send Message' endpoint has a maximum payload size of 100MB. However, it is possible to send much larger messages (up to 20GB) by breaking up the message into chunks and transmitting it over multiple requests.

Note: Some workflowIDs do not support chunking because it is not currently supported in the MESH UI and older versions of the MESH client. Check with your receiving organisation before sending messages with this endpoint. To send a chunked message:

  1. Split it into separate files
  2. Compress the individual chunks separately with the same compression program (e.g. gzip).
    1. DO NOT compress a large file and then split the compressed version
  3. Upload the first file using the normal Send message endpoint.
    1. Include the Mex-Chunk-Range header with a value of 1:n where n is the number of separate files your big data is split into.
    2. Capture the messageId field in the returned JSON.
  4. Upload subsequent files in the correct order using the chunked message endpoint

Note: fewer headers are required for the chunked message endpoint because Spine uses the relevant metadata from the initial (Mex-Chunk-Header=1:n) call to the Send message endpoint.

Request

Suppose Bob has a large file to send to Alice. In this example we will use message.txt. It is easily small enough to send in a single request but we will chunk it anyway to illustrate the API calls.

    ls -sh message.txt
    4.0kb message.txt
  cat message.txt
    
    Hi Alice,

    This is Bob. It's really nice that we can communicate via SPINE!

    I hope to hear more from you in the future,

    Bob.

First we break up our one "large" file into two smaller files. We will transmit one per request.

    split -b 100 message.txt message.txt_
    ls -sh message.txt_*

Large messages should be compressed to reduce the bandwidth and storage requirements for Spine.

    for chunk_file in message.txt_*; do
        gzip -k -f $chunk_file;
    done
    ls -sh message.txt_*.gz
    
    4.0kb message.txt_aa.gz
    4.0kb message.txt_ab.gz
    curl -k \
    --cacert 'mesh-ca.pem' \
    --key 'mesh-client-key.pem' \
    --cert 'mesh-client-cert.pem' \
    --request 'POST' \
    --header 'Authorization: NHSMESH X26HC006:2c6e938e-9a72-4a7a-9664-96ac1f341331:0:202006041718:8a2bb02f280f544423503c465df23359e8302c039e5113cc0d88e3c1b7283482' \
    --header 'Content-Type: application/octet-stream' \
    --header 'Mex-From: X26HC006' \
    --header 'Mex-To: X26HC005' \
    --header 'Mex-WorkflowID: API-DOCS-TEST' \
    --header 'Mex-FileName: message.txt.gz' \
    --header 'Mex-LocalID: api-docs-bob-sends-alice-a-chunked-file' \
    --header 'Mex-Chunk-Range: 1:2' \
    --header 'Content-Encoding: gzip' \
    --data-binary '@message.txt_aa.gz' \
    https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox
    curl -k \
    --cacert 'mesh-ca.pem' \
    --key 'mesh-client-key.pem' \
    --cert 'mesh-client-cert.pem' \
    --request 'POST' \
    --header 'Authorization: NHSMESH X26HC006:06bf0527-ba77-47f0-b22f-d7d08a88ad26:0:202006041718:d41a9c41e98159e180234ba7940a3a208c67389dc2cb22516dd4a11f57ccfabc' \
    --header 'Mex-Chunk-Range: 2:2' \
    --data-binary '@./message.txt_ab.gz' \
    https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox/\
    20200601122152994285_D59900/2

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
messageID
String
The ID of the message
Required
chunkNo
Integer
The index number of the chunk
Example: 1
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required
Content-Type
String
Type of sent content
Example: application/octet-stream
Required
Mex-Chunk-Range
String (integer:integer)
describes which chunk of the range is sent.
Example: 124
Required

Response

HTTP status: 202
Accepted
Body
Content type: application/json
Schema
Name Description
object
messageID
string
Unique message ID, identical to initial Send message endpoint
Example: 20200529155357895317_3573F8
blockID
integer
ID assigned to the block
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status

Send message

post
/messageexchange/{mailboxID}/outbox

Overview

Use this endpoint to send a message via MESH. This must be done via the POST command to your virtual outbox. The message recipient is specified in the request headers, with the message contained in the request body.

Messages larger than 100MB

100MB (20MB on internet) is the largest data payload the MESH server will accept in a single request. Larger messages should be compressed to reduce bandwidth and data storage on Spine. If compression does not sufficiently reduce the message size enough for transmission in a single request then it can be broken up into smaller chunks and transmitted separately provided:

  1. The total compressed size of the message is < 100MB (this is the Spine upper limit for a single message).
  2. The receiver mailboxId and workflowId support the downloading of chunked messages. (The MESH UI and older versions of the MESH client do not have this support)

To correctly break the outbound message into valid chunks:

  1. Split the uncompressed message into n ordered chunks such that each (compressed) chunk is smaller than 20MB.
  2. Independently compress each chunk with the same compression algorithm (e.g. gzip).
  3. The first (compressed) chunk of the message should be transmitted using this endpoint (the regular send message endpoint). The optional Mex-Chunk-Range header must be included with a value 1:n to tell Spine that this will be a chunked message and it should wait for n-1 other requests before delivering the message. The messageId of this initial server response must be captured as it is a required path element of the Send chunked message url.

The workflowId should always be set, some workflowIds are restricted which means the mailbox sender and recipient must be configured for the workflowId being sent.

To discover the recipient mailbox either the endpointlookup endpoint can be used or for certain workflows demographic details can be included in the Mex-To field.

It is good practice to catpure the returned messageId as this provides a unique identifer which can be used for message tracking.

Request
    curl -k \
    --request 'POST' \
    --cacert 'mesh-ca.pem' \
    --key 'mesh-client-key.pem' \
    --cert 'mesh-client-cert.pem' \
    --header 'Authorization: NHSMESH X26HC006:c1f2df9c-fe9e-4d11-ba78-49a8bc705eb4:0:202006041718:b2539ba3a3d086ea01c8f18488e227a5e8b0418b95870c73fd83a368e6642d49' \
    --header 'Content-Type: application/octet-stream' \
    --header 'Mex-From: X26HC006' \
    --header 'Mex-To: X26HC005' \
    --header 'Mex-WorkflowID: API-DOCS-TEST' \
    --header 'Mex-FileName: None' \
    --header 'Mex-LocalID: api-docs-bob-greets-alice' \
    --data 'This is a message' \
    https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox
Response
 {"messageID": "20200529155357895317_3573F8"}

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required
Content-Type
String
Type of sent content
Example: application/octet-stream
Required
Mex-FileName
String
{Original File Name}
Example: {Message content should have this file name after receipt}
Required
Mex-From
String
Sending organisation's mailbox ID
Example: {Sending organisation's mailbox ID}
Required
Mex-To
String
Recipient mailbox ID
Example: {Recipient Mailbox ID}
Required
Mex-WorkflowID
String
Identifies the Business Workflow associated with the message
Example: {Workflow ID}
Required
Mex-Chunk-Range
String
1:{n} {if first of n chunks, see Send chunked message}
Mex-Content-Compress
String
Flag to indicate that the contents have been automically compressed by the client using GZip compression
Mex-Content-Encrypted
String
Indicate to the receiver that contents are encrypted
Mex-Localid
String
A unique ID generated by you, must not contain Patient Identifiable Data PID
Mex-Subject
String
Subject line for message to SMTP MESH mailboxes
Content-Encoding
String
Algorithm used to compress the file e.g. 'gzip'
Mex-MessageType
String
DATA
Required
Mex-ProcesslID
String
{Local process identifer}
mex-Content-Checksum
String
Checksum of the original file contents

Response

HTTP status: 202
Accepted
Body
Content type: application/json
Schema
Name Description
object
messageID
string
Unique Id assigned by the MESH server
Example: 20200529155357895317_3573F8
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status
HTTP status: 417
Invalid Recipient or the workflow is restricted
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
errorEvent
string
Status event
errorCode
integer
Status code
Example: 417
errorDescription
string
Description of the status

Validate a mailbox (Handshake)

get
/messageexchange/{mailboxID}

Overview

Use this endpoint to check that MESH can be reached and that the authentication you are using is correct. This endpoint only needs to be called once every 24 hours. This endpoint updates the details of the connection history held for the mailbox and is similar to a keep-alive or ping message, in that it allows monitoring on the Spine to be aware of the ongoing utilisation of a mailbox despite a lack of traffic.

Request
curl -k \
  --request 'GET' \
  --cacert 'mesh-ca.pem' \
  --key 'mesh-client-key.pem' \
  --cert 'mesh-client-cert.pem' \
  --header 'Authorization: NHSMESH X26HC005:1c820cd4-be3e-43ff-807f-e65362892722:0:202006041718:3401727c81320539a9b3cf835d1e7748f18bc49ab333a6c1841b67df88f2e5f7' \
  --header 'Mex-ClientVersion: ApiDocs==0.0.1' \
  --header 'Mex-OSArchitecture: x86_64' \
  --header 'Mex-OSName: Linux' \
  --header 'Mex-OSVersion: #44~18.04.2-Ubuntu' \
  https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC005
Response
  {"mailboxId" : "X26HC005"}

Request

Path parameters
Name Description
mailboxID
String
The ID of the mailbox
Example: MAILBOX01
Required
Headers
Name Description
Authorization
String
Authentication headers
Example: Authorization: NHSMESH NONFUNC01:jt81ti68rlvta7379p3ng949rv:1:201511201038:291259e6a73cde3278f99cd5bd3c7ec9b3d1d5479077a8f711bddf58073d5555
Required
Mex-ClientVersion
String
Client version number
Example: ApiDocs==0.0.1
Required
Mex-OSName
String
Operating system name
Example: Linux
Required
Mex-OSVersion
String
Operating system version
Example: #44~18.04.2-Ubuntu
Required
Mex-OSArchitecture
String
{Operating System Architecture}
Mex-JavaVersion
String
{JVM Version Number}

Response

HTTP status: 200
OK
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 400
Bad Request
Body
Content type: application/json
Schema
Name Description
object
HTTP status: 403
Authentication failed
Body
Content type: application/json
Schema
Name Description
object
messageID
string
ID of the allocated message
Example: 20200529155357895317_3573F8
errorEvent
string
Status event
Example: status event
errorCode
integer
Status code
Example: 403
errorDescription
string
Description of the status
Example: Description of the status