# NHS Spine

ebMS 2.0 over mutual TLS with NHS party identifiers and CPA ids - the national health messaging network of England.

The Spine is the national service that connects health and care systems in England. Its asynchronous exchanges run over ebXML Message Service (ebMS 2.0) - each message a SOAP 1.1 envelope whose header names the sending and receiving parties, the service and the action, with the clinical payloads attached as MIME parts.

## What the Spine mandates {#what-the-spine-mandates}

| Requirement | Where it comes from | In Zato |
| --- | --- | --- |
| ebMS 2.0 message structure | The Spine's External Interface Specification | [ebXML messaging](https://zato.io/docs/dev/soap/ebxml/index.html) over an outgoing SOAP connection |
| NHS party identifiers with a type attribute | The Spine's addressing conventions | `from_party_type` and `to_party_type` on the call |
| CPA ids agreed during onboarding | The Spine directory | `cpa_id` on the call |
| Mutual TLS on the health and social care network | Spine connection agreements | The connection's **Client certificate** and **Client key** |

## Configuring the connection {#configuring-the-connection}

**Step 1.** Create the outgoing connection under **Connections** > **Outgoing** > **SOAP** with the message handling service's address. ebMS runs over SOAP 1.1, which is the connection's default version.

**Step 2.** In the Security tab, set the client certificate and key paths issued for your endpoint - the Spine authenticates message handlers at the TLS layer:

**Step 3.** The exchange itself is one call - the platform builds the `eb:MessageHeader` with a fresh message id and timestamp, the `eb:Manifest`, and the MIME package:

```python
info = EbXMLInfo()
info.from_party = 'my-party-id'
info.from_party_type = 'urn:nhs:names:partyType:ocs+serviceInstance'
info.to_party = 'spine-party-id'
info.to_party_type = 'urn:nhs:names:partyType:ocs+serviceInstance'
info.cpa_id = 'S2001919A2011852'
info.conversation_id = self.cid
info.service = 'urn:nhs:names:services:pdsquery'
info.action = 'QUPA_IN000006UK02'

part = Part()
part.content_id = 'payload-1'
part.content_type = 'application/xml'
part.data = hl7v3_query

ack = self.soap['Spine MHS'].invoke_ebxml(info, [part])
```

The reply's parsed header comes back with `ref_to_message_id` pointing at the message it acknowledges - the [ebXML page](https://zato.io/docs/dev/soap/ebxml/index.html) covers the whole call in detail.

## Learn more {#learn-more}

- [SOAP integrations](https://zato.io/docs/dev/soap/) - Envelopes, versions and Python objects instead of XML
- [SOAP as Python objects](https://zato.io/docs/dev/soap/python-objects/) - Build requests and read responses with dot access, no schemas
- [SOAP security](https://zato.io/docs/dev/soap/security/) - WS-Security, credentials in the body and client certificates
- [MTOM and SwA attachments](https://zato.io/docs/dev/soap/attachments/) - Binary content out of the envelope and into MIME parts
- [SOAP mandates](https://zato.io/docs/dev/soap/mandates/) - What each national and sector profile requires, and how to meet it
- [SOAP tutorial](https://zato.io/tutorials/soap/calling.html) - Call any SOAP service with Python objects, start to finish
