SOAP (Simple Object Access Protocol) web services wrap HL7 v2 messages inside XML SOAP envelopes and transmit them over HTTP or HTTPS. The SOAP envelope contains optional headers (for routing, security tokens, or timestamp assertions) and a body that carries the HL7 message as a serialized XML or string element. WSDL (Web Services Description Language) files define the service interface—operations, input/output message types, and binding details. SOAP is a structured, contract-driven alternative to REST, widely used in healthcare for B2B messaging and IHE (Integrating the Healthcare Enterprise) transaction implementations.
What is SOAP
SOAP is a messaging protocol defined by W3C (World Wide Web Consortium) in the SOAP 1.2 specification. It uses XML to structure a message envelope containing optional header blocks (for metadata, security assertions, or routing rules) and a mandatory body block carrying the actual payload. The SOAP envelope is transported over HTTP/HTTPS, with a single operation per request mapped to an HTTP POST.
In the healthcare context, SOAP web services carry HL7 v2 messages as the SOAP body payload. The sender constructs a SOAP request with the HL7 message (as XML or as a serialized string) and posts it to the receiver's WSDL-defined endpoint. The receiver parses the SOAP envelope, extracts the HL7 message, processes it, and returns a SOAP response containing the HL7 ACK or reply message.
SOAP is a contract-first transport: both parties agree on a WSDL service definition that describes the operations, message types, and bindings before any data flows. This formality makes SOAP well-suited to regulated environments (healthcare, finance) where audit trails, compliance, and explicit contracts are mandatory.
How it works
The sender and receiver agree on a WSDL file (published by the receiver) that defines:
- Service name and port(s)
- Operations (e.g.,
SubmitMessage,QueryPatient) - Input message type: The HL7 message structure or wrapper
- Output message type: The HL7 ACK or response
- SOAP binding: HTTP POST, SOAP/1.2 over HTTP
- Endpoint URL: The receiver's HTTPS endpoint (e.g.,
https://ehr.hospital.org/hl7/soap)
The sender builds a SOAP request envelope:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:hl7="urn:hl7-org:v2xml">
<soap:Header>
<security:UsernameToken xmlns:security="...">
<security:Username>sender_system</security:Username>
<security:Password>...</security:Password>
</security:UsernameToken>
<Timestamp>20260701T120000Z</Timestamp>
</soap:Header>
<soap:Body>
<hl7:SubmitMessageRequest>
<hl7:Message>
MSH|^~&|REGMGR|HOSPITAL|HL7RECV|HOSPITAL|20260701120000||ADT^A01^ADT_A01|MSG000123|P|2.5.1
...
</hl7:Message>
</hl7:SubmitMessageRequest>
</soap:Body>
</soap:Envelope>
The sender posts this XML to the HTTPS endpoint via HTTP POST with Content-Type: application/soap+xml. The receiver parses the envelope, validates the headers (authentication, timestamp), extracts the HL7 message from the body, processes it, and constructs a SOAP response:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:hl7="urn:hl7-org:v2xml">
<soap:Body>
<hl7:SubmitMessageResponse>
<hl7:AckMessage>
MSH|^~&|HL7RECV|HOSPITAL|REGMGR|HOSPITAL|20260701120000||ACK^A01^ACK|MSG000123|P|2.5.1
MSA|AA|MSG000123|Success
</hl7:AckMessage>
<hl7:Status>SUCCESS</hl7:Status>
</hl7:SubmitMessageResponse>
</soap:Body>
</soap:Envelope>
The HTTP response (200 OK) carries this SOAP response back to the sender. The sender parses it, verifies the status, and logs the result. The entire exchange is synchronous and request-response.
Sender Receiver
| |
|-- TLS Handshake ---------------------------> |
|<-- TLS Handshake Complete ------------------|
| |
|-- HTTP POST /hl7/soap ---------> |
| Content-Type: application/soap+xml |
| Content-Length: 1024 |
| |
| <soap:Envelope> |
| <soap:Header> |
| <UsernameToken>...</UsernameToken>
| </soap:Header> |
| <soap:Body> |
| <hl7:SubmitMessageRequest> |
| <hl7:Message>MSH|...|</hl7:Message>
| </hl7:SubmitMessageRequest> |
| </soap:Body> |
| </soap:Envelope> |
| |
|<-- HTTP/1.1 200 OK --------- <--------|
| Content-Type: application/soap+xml |
| Content-Length: 512 |
| |
| <soap:Envelope> |
| <soap:Body> |
| <hl7:SubmitMessageResponse> |
| <hl7:AckMessage>MSH|...|</hl7:AckMessage>
| <hl7:Status>SUCCESS</hl7:Status>
| </hl7:SubmitMessageResponse>|
| </soap:Body> |
| </soap:Envelope> |
| |
|-- [TLS close] -----------------------> |
| |
When to use it
SOAP web services are appropriate when:
- Contract-driven exchange: Both parties have agreed on a WSDL and expect strict schema validation and formal interface definitions.
- IHE ITI transactions: The integration follows an IHE profile (e.g., ITI-41 Provide and Register Document Set) that mandates SOAP and WSDL.
- Regulated industries: Compliance requirements (e.g., HIPAA audit logs, legal holds) demand explicit contracts and formal message schemas.
- Legacy enterprise integration: Your organization has existing SOAP/WS infrastructure (application servers, enterprise service buses) and wants to reuse it for HL7.
- WS-Security requirements: You need token-based security (SAML, X.509 certificates) or advanced header mechanisms that REST and simple HTTP do not standardize.
- Complex routing and policy: SOAP allows header-level routing rules, quality-of-service assertions, and policy chains (WS-Policy) that simplify orchestration in an enterprise service bus.
Avoid SOAP if:
- Rapid integration: You need a quick connection to a simple endpoint. REST or HL7 over HTTPS is faster to stand up.
- Mobile or IoT: Mobile clients and edge devices handle HTTP/REST better than SOAP/XML parsing.
- Microservices: Modern cloud-native stacks favor REST and asynchronous patterns (e.g., message queues, webhooks) over synchronous SOAP.
- Firewall complexity: Some corporate proxies and firewalls have trouble with SOAP/WS-* due to the overhead of XML and header processing.
Configuration parameters
| Parameter | Value | Notes |
|---|---|---|
| Protocol | HTTPS (TLS 1.2 or 1.3 recommended) | HTTP may be used in development; production must use HTTPS. |
| Port | 443 (standard HTTPS) or custom (e.g., 8080 for development) | Check WSDL for the binding endpoint URL. |
| HTTP Method | POST only | SOAP operations are all POST; no GET, PUT, DELETE. |
| Content-Type | application/soap+xml | Per SOAP 1.2 spec; legacy systems may use text/xml with SOAP 1.1. |
| Character Encoding | UTF-8 | SOAP XML must be UTF-8. Declare in XML prolog: <?xml version="1.0" encoding="UTF-8"?>. |
| SOAP Version | 1.2 (preferred) or 1.1 | SOAP 1.2 is the W3C standard; SOAP 1.1 is legacy but still in use. Namespace differs: 1.2 uses http://www.w3.org/2003/05/soap-envelope, 1.1 uses http://schemas.xmlsoap.org/soap/envelope/. |
| WSDL Location | Published by receiver (e.g., https://ehr.hospital.org/hl7/soap?wsdl) | The WSDL file defines all binding and operation details. Client must validate against the WSDL before sending. |
| Binding Style | Document (literal) or RPC (encoded) | Document/literal is preferred (WS-I compliant); RPC is legacy. |
| Timeout | 30–120 seconds | Receiver processing time; set per operation. Typical response should arrive within 5–10 seconds. |
| Authentication | Username/Password (WS-Security), SAML token, X.509 certificate | Specified in WSDL. UsernameToken is common; SAML for federated scenarios; mutual TLS for B2B. |
| Message Exchange Pattern (MEP) | Request-Response (RPC-style) or one-way | Request-Response is standard (synchronous). One-way requires asynchronous callback. |
| SOAP Fault Handling | HTTP 200 OK with SOAP Fault in body, or HTTP 500 Internal Server Error | Faults are returned as SOAP Fault elements in the response body, not HTTP errors. Check the SOAP Fault structure for details. |
Security
TLS Encryption: SOAP messages are XML, which is human-readable and must be encrypted in transit. Use TLS 1.2 or higher over HTTPS (port 443). Both client and server validate certificate chains; self-signed certificates are not acceptable in production.
Authentication and Authorization: SOAP defines WS-Security (OASIS standard) for embedding security credentials in the SOAP header:
- UsernameToken: Username and password (plain or hashed with a nonce); password is transmitted inside TLS, so the message itself is not readable without the encryption.
- SAML Assertion: A signed XML token issued by an identity provider; embeds subject, conditions (time, audience), and claims. Used for federated scenarios.
- X.509 Certificate: Client certificate in the SOAP header or via mutual TLS at the transport layer.
- Kerberos Token: Enterprise-grade authentication for on-premises scenarios.
Example WS-Security UsernameToken header:
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
soap:mustUnderstand="true">
<wsse:UsernameToken>
<wsse:Username>sender_system</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
secret_password
</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
Message Integrity and Non-Repudiation: SOAP can sign the entire body or specific elements using XML Signature (xmldsig). The signature proves the message was not tampered with and that it came from the claimed sender.
Example signed SOAP message (signature element in header):
<soap:Header>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" />
<ds:Reference URI="#body">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<ds:DigestValue>...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue>
</ds:Signature>
</soap:Header>
Audit Logging: SOAP messages must be logged for compliance. Store the full SOAP envelope (minus sensitive passwords) for audit trails. Log timestamp, sender, operation, and status code.
Pros & cons
Pros:
- Contract-driven: WSDL defines the interface explicitly. Both parties know exactly what to expect, reducing integration surprises.
- Standards-based: W3C SOAP 1.2, OASIS WS-Security, and WS-I profiles ensure interoperability across vendor platforms.
- Rich security: WS-Security allows multiple layers of authentication and encryption (SAML, X.509, signed bodies) in a standardized way.
- Enterprise integration: Works seamlessly with enterprise application servers (Oracle Fusion, SAP, Microsoft BizTalk) and enterprise service buses (Apache ServiceMix, WSO2 ESB).
- Formal audit trail: WSDL contracts and signed SOAP messages create a clear audit trail for compliance.
- Typed messages: XML schema validation ensures structure is enforced before processing.
- Standardized error handling: SOAP Fault elements provide a structured way to report errors and faults.
Cons:
- XML overhead: SOAP envelopes add significant overhead (2–3x larger than JSON payloads). For high-volume messaging, this becomes a network and parsing bottleneck.
- Complexity: WSDL, namespace handling, and schema validation require more expertise than simple HTTP/REST. Debugging SOAP issues is harder.
- Verbose tooling: SOAP clients require specialized libraries (e.g., Apache Axis, WS-* stacks) and code generation from WSDL. REST uses simple HTTP libraries.
- Synchronous only: SOAP is request-response; it does not map well to asynchronous queuing patterns.
- Firewall and proxy issues: Some corporate proxies and WAFs struggle with SOAP/WS-* due to the complexity of the XML and headers. Occasionally, proxies strip or mishandle WS-Addressing or WS-Policy headers.
- Performance: TLS handshake + XML parsing + schema validation adds latency compared to REST or MLLP.
- Maintenance: WSDL files require synchronization between sender and receiver. Changes to the schema force updates on both sides.
Examples
Example 1: Wire-level SOAP request and response
Client sends an HL7 ADT message wrapped in a SOAP envelope:
POST /hl7/soap HTTP/1.1
Host: ehr.hospital.org
Content-Type: application/soap+xml; charset=UTF-8
Content-Length: 1847
SOAPAction: "SubmitMessage"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:hl7="urn:hl7-org:v2xml"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<soap:Header>
<wsse:Security soap:mustUnderstand="true">
<wsse:UsernameToken>
<wsse:Username>REGMGR</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
secret123
</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Created>2026-07-01T12:00:00Z</Created>
</Timestamp>
</soap:Header>
<soap:Body>
<hl7:SubmitMessageRequest>
<hl7:Message>MSH|^~&|REGMGR|HOSPITAL|HL7RECV|HOSPITAL|20260701120000||ADT^A01^ADT_A01|MSG000123|P|2.5.1
EVN|A01|20260701120000|||SYSTEM
PID|1||MRN123456^^^HOSPITAL~12345^^^NPI||Doe^Jane^M||19800615|F|||123 Main St^^Chicago^IL^60601^USA||^^^^^(312)555-0123|^^^^^(312)555-0124||S|C|||||||||||||||||N
NK1|1|Doe^John|SPO|123 Main St^^Chicago^IL^60601||^^^^^(312)555-0199
PV1|1|I|CARDIO^ICU^BED01^A|H|||001234^Smith^John^Dr.||CAR|||N||||2|||001234^Smith^John^Dr.|||||||||||||||||||20260701100000</hl7:Message>
</hl7:SubmitMessageRequest>
</soap:Body>
</soap:Envelope>
Server responds with an HL7 ACK wrapped in a SOAP envelope:
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=UTF-8
Content-Length: 712
Date: Wed, 01 Jul 2026 12:00:01 GMT
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:hl7="urn:hl7-org:v2xml">
<soap:Body>
<hl7:SubmitMessageResponse>
<hl7:AckMessage>MSH|^~&|HL7RECV|HOSPITAL|REGMGR|HOSPITAL|20260701120000||ACK^A01^ACK|MSG000123|P|2.5.1
MSA|AA|MSG000123|Patient admitted successfully</hl7:AckMessage>
<hl7:Status>SUCCESS</hl7:Status>
<hl7:MessageId>MSG000123</hl7:MessageId>
</hl7:SubmitMessageResponse>
</soap:Body>
</soap:Envelope>
Example 2: Annotated SOAP envelope structure
Breakdown of the SOAP envelope:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<!-- Namespace binding for SOAP 1.2 -->
<soap:Header>
<!-- Zero or more header blocks, typically for metadata, routing, or security -->
<!-- All header attributes (role, mustUnderstand, relay, encodingStyle) are optional -->
</soap:Header>
<soap:Body>
<!-- Mandatory body block containing the message or fault -->
<!-- For a request: wrapped operation element (e.g., <hl7:SubmitMessage>) -->
<!-- For a fault: <soap:Fault> element -->
</soap:Body>
</soap:Envelope>
Detailed header example:
<soap:Header>
<!-- WS-Addressing headers (optional, but common for routing in service buses) -->
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">SubmitMessage</wsa:Action>
<wsa:MessageID>urn:uuid:550e8400-e29b-41d4-a716-446655440000</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://sender.hospital.org/callback</wsa:Address>
</wsa:ReplyTo>
<!-- WS-Security (UsernameToken) -->
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
soap:mustUnderstand="true">
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>SENDER_SYS</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
encrypted_or_plaintext_password
</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
FZMzcHlSLG2g8y7xEw==
</wsse:Nonce>
<wsu:Created>2026-07-01T12:00:00Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
<!-- Timestamp for replay attack prevention -->
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
soap:mustUnderstand="false">
<wsu:Created>2026-07-01T12:00:00Z</wsu:Created>
<wsu:Expires>2026-07-01T12:05:00Z</wsu:Expires>
</wsu:Timestamp>
</soap:Header>
Example 3: WSDL service definition (partial)
A minimal WSDL file defining the HL7 SOAP service:
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HL7Service"
targetNamespace="urn:hl7-org:v2xml"
xmlns:tns="urn:hl7-org:v2xml"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types>
<schema targetNamespace="urn:hl7-org:v2xml" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="HL7Message" type="xsd:string" />
<element name="HL7Response" type="xsd:string" />
<element name="Status" type="xsd:string" />
</schema>
</types>
<message name="SubmitMessageRequest">
<part name="message" element="tns:HL7Message" />
</message>
<message name="SubmitMessageResponse">
<part name="ackMessage" element="tns:HL7Response" />
<part name="status" element="tns:Status" />
</message>
<portType name="HL7PortType">
<operation name="SubmitMessage">
<input message="tns:SubmitMessageRequest" />
<output message="tns:SubmitMessageResponse" />
</operation>
</portType>
<binding name="HL7Binding" type="tns:HL7PortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="SubmitMessage">
<soap:operation soapAction="SubmitMessage" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="HL7Service">
<port name="HL7Port" binding="tns:HL7Binding">
<soap:address location="https://ehr.hospital.org:443/hl7/soap" />
</port>
</service>
</definitions>
Example 4: Failure-mode SOAP Fault
Client sends a SOAP request; server detects a validation error and returns a SOAP Fault:
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=UTF-8
Content-Length: 512
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<soap:Fault>
<Code>
<Value>soap:Sender</Value>
<Subcode>
<Value>tns:ValidationError</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en">Message validation failed</Text>
</Reason>
<Detail>
<hl7Error xmlns="urn:hl7-org:v2xml">
<errorCode>103</errorCode>
<errorDescription>Invalid patient ID format</errorDescription>
<failedSegment>PID|1||INVALID|||</failedSegment>
<timestamp>2026-07-01T12:00:02Z</timestamp>
</hl7Error>
</Detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Server error log:
[2026-07-01 12:00:02.123] WARN [SOAP-HL7-Handler] Validation error for SOAP request from 192.0.2.10:
tns:ValidationError: Message validation failed
PID segment field 3 (Patient ID): expected format NNN^^^SYSTEM, got 'INVALID'
Request ID: MSG000123
Sender: REGMGR
Vorro support for SOAP web services
Vorro's HL7 engine includes a SOAP web-service listener that accepts POST requests with SOAP envelopes containing HL7 messages. Vorro parses the SOAP envelope, extracts the HL7 message from the body, validates it against the HL7 schema, and passes it through the transformation pipeline. Responses are wrapped in a SOAP envelope and returned with HTTP 200 OK and a status code embedded in the SOAP body (e.g., <hl7:Status>SUCCESS</hl7:Status>).
Vorro can generate WSDL definitions from the HL7 message types it supports, or it can import an existing WSDL and validate incoming SOAP messages against it. Authentication is handled via WS-Security UsernameToken (stored in Vorro's credential vault) or mutual TLS (client certificate validation).
When acting as a SOAP client, Vorro's SOAP sender can post messages to external SOAP endpoints. Vorro constructs the SOAP envelope, includes the necessary security headers (UsernameToken, Timestamp, Signature), and handles SOAP Faults returned by the receiver.
Related pages
- HL7 Transport: HL7 over HTTPS/REST
- HL7 Transport: Shared Folder / File-Drop
- ADT^A01 Message: Admission
- ORM Message: Order
- ORU Message: Lab Result
