Skip to content

SOAP Source

The SOAP source starts an HTTP server that exposes a SOAP web service endpoint, accepting XML-encoded SOAP envelopes from legacy healthcare systems. It parses the SOAP Body and passes the inner XML payload into the channel pipeline.

If a wsdl_path is configured, the service description is automatically served at ?wsdl, allowing clients to discover the endpoint contract.

source:
type: soap
port: 8443
wsdl_path: ./wsdl/cda-receiver.wsdl
service_name: CDAReceiverService
tls:
cert_file: ./certs/server.crt
key_file: ./certs/server.key
auth:
type: wsse
username: ehr_system
password: ${WSSE_PASSWORD}
PropertyTypeRequiredDefaultDescription
portintYesTCP port the SOAP server binds to.
wsdl_pathstringNoPath to a WSDL file. When set, the WSDL is served at ?wsdl.
service_namestringNoSOAP service name advertised in the WSDL and response headers.
tlsobjectNoTLS certificate and key for HTTPS.
authobjectNoAuthentication configuration.

The auth block supports two strategies for SOAP endpoints:

auth:
type: basic
username: ehr_system
password: ${BASIC_PASSWORD}
auth:
type: wsse
username: ehr_system
password: ${WSSE_PASSWORD}

WS-Security credentials are validated from the SOAP envelope’s <wsse:Security> header.

A CDA document receiver that accepts C-CDA clinical documents over SOAP and converts them to FHIR:

channels/cda-receiver/channel.yaml
id: cda-receiver
enabled: true
group: clinical-docs
source:
type: soap
port: 8443
wsdl_path: ./wsdl/cda-receiver.wsdl
service_name: CDAReceiverService
tls:
cert_file: ./certs/server.crt
key_file: ./certs/server.key
auth:
type: wsse
username: ehr_system
password: ${WSSE_PASSWORD}
transformer: cda-to-fhir.ts
destinations:
- ehr_fhir
- archive

A TypeScript transformer that extracts key fields from a CDA XML document and produces a FHIR DocumentReference:

transforms/cda-to-fhir.ts
export default function transform(msg: IntuMessage): IntuMessage {
const xml = msg.payload;
const titleMatch = xml.match(/<title>(.*?)<\/title>/);
const idMatch = xml.match(/<id root="(.*?)"/);
const effectiveTimeMatch = xml.match(/<effectiveTime value="(\d{8})"/);
const documentReference = {
resourceType: "DocumentReference",
status: "current",
type: {
coding: [
{
system: "http://loinc.org",
code: "34133-9",
display: "Summarization of Episode Note",
},
],
},
description: titleMatch?.[1] ?? "CDA Document",
date: effectiveTimeMatch?.[1]
? `${effectiveTimeMatch[1].slice(0, 4)}-${effectiveTimeMatch[1].slice(4, 6)}-${effectiveTimeMatch[1].slice(6, 8)}`
: undefined,
content: [
{
attachment: {
contentType: "application/xml",
data: Buffer.from(xml).toString("base64"),
},
},
],
masterIdentifier: idMatch?.[1]
? { system: "urn:oid:" + idMatch[1], value: idMatch[1] }
: undefined,
};
msg.payload = JSON.stringify(documentReference);
return msg;
}