Sending a CDA Document to an HIE¶
This recipe configures a channel to submit a CDA document to a Health Information Exchange (HIE) using IHE ITI-41 Provide and Register Document Set-b. The same configuration works for XDS.b (Affinity Domain) and XDR (point-to-point). Only the endpoint URL changes.
It assumes you already have a channel that produces or receives the CDA; the focus here is the submission destination.
What QIE supports¶
IHE transactions. QIE has built-in operations for the most common IHE transactions, with auto-generated SOAP envelopes:
| Profile | Built-in transactions |
|---|---|
| XDS.b | ITI-41 (Provide and Register), ITI-42 (Register), ITI-18 (Adhoc Query), ITI-43 (Retrieve Document Set) |
| PIX / PIXv3 | ITI-44 (Patient Identity Feed), ITI-45 (PIXv3 Query) |
| PDQ | ITI-47 (Patient Demographics Query) |
| XCA | ITI-38 (Cross-Community Query), ITI-39 (Cross-Community Retrieve) |
| XCPD | ITI-55 (Cross-Community Patient Discovery) |
| HPD | ITI-58 (Provider Information Query) |
Any other SOAP-based IHE transaction can be configured with a standard SOAP Web Service connection. Load the actor's WSDL and the operations become available in the SOAP Sender. In practice, QIE can implement any IHE transaction QIE can be given a WSDL for.
CDA documents. ITI-41 carries the document as a binary attachment, so QIE can submit any CDA R2 / C-CDA document type: Continuity of Care Document (CCD), Discharge Summary, Progress Note, Referral Note, Care Plan, etc. The document type is communicated to the recipient through the Class Code (typically LOINC) and Format Code (an IHE/HITSP template OID) metadata fields. The HIE supplies the specific values to use.
XDS.b vs. XDR. ITI-41 is the same SOAP call in both. XDS.b targets a Document Repository actor in an Affinity Domain; XDR delivers point-to-point to a Document Recipient actor. The QIE configuration is identical; only the endpoint URL changes.
What you need from the HIE before you start¶
QIE cannot invent the connection details. These come from the HIE's onboarding packet:
- The ITI-41 endpoint URL (UAT and production).
- TLS requirements, server-only TLS or mutual TLS, and any cipher restrictions.
- For mutual TLS: which client certificate to present. The HIE only needs your public certificate.
- The required metadata values for the XDS.b submission: Class Code, Format Code, Confidentiality Code, Practice Setting Code, Facility Type Code, Type Code, and any expected schemes.
- Your Document Source ID, the OID identifying your organization as a Document Source. The HIE assigns or accepts this value.
- The patient identifier domain the HIE expects (often the affinity-domain OID).
- Whether the HIE expects MTOM/XOP framing or plain SOAP attachments.
- Test patient/document requirements for onboarding.
Step 1: Import any required certificates¶
If the HIE requires TLS or mutual TLS, import the HIE's server certificate (and your client key, if mTLS is required) on the Certificate Management page. Skip this step for plain-HTTP test endpoints.
Step 2: Create the IHE Web Service Connection¶
On the Web Service Connections page, create one connection per HIE actor endpoint URL. Many HIEs split actors across different URLs (Document Repository, Registry, PIX Manager, etc.); use one connection per actor and check only the transactions that actor serves.
| Field | Value |
|---|---|
| Type | IHE Web Service Profiles |
| Endpoint URL | The HIE-supplied ITI-41 endpoint |
| Operations | Check Provide and Register Document Set-b (ITI-41) |
| TLS Version | Match the HIE's requirement (commonly TLSv1.2 or Allow All Supported Versions) |
| Trust Policy | Trust Selected Certificates. Pick the HIE's server cert |
| Client Auth | Required if the HIE mandates mTLS, then pick your client key in Client Cert |
| Cached Conn. | A non-zero value (e.g. 4) if you expect sustained throughput; the default 0 is fine for low volume |
Step 3: Add a SOAP Sender destination¶
On the channel that produces the CDA, add a destination node. Selecting an IHE Web Service Connection makes the destination a SOAP Sender automatically; the configuration fields are:
| Field | Value |
|---|---|
| Connection | The IHE connection from Step 2 |
| Binding | XDS_soap12_binding (SOAP 1.2, because ITI-41 is bound to SOAP 1.2) |
| Operation | ProvideAndRegisterDocumentSetRequest |
| Use MTOM | Leave unchecked unless the HIE requires MTOM/XOP framing |
| Request Timeout / Ack Timeout | 15000 (ms) is a sensible starting point; raise for slow HIEs |
| Retry Limit | 5 |
| Use Ack | Checked |
When you select the operation, QIE auto-generates the SOAP envelope template, starting <xdsb:ProvideAndRegisterDocumentSetRequest> with the IHE-standard <wsa:Action> header urn:ihe:iti:2007:ProvideAndRegisterDocumentSet-b and the registry-object skeleton populated with node-tag placeholders.
Step 4: Attach the CDA document¶
Open the Attachments dialog on the SOAP Sender. Add one attachment per CDA document being submitted.
| Field | Value |
|---|---|
| Source | Message Cache or Message Node, depending on where the CDA bytes live in your channel |
| Value | The cache key or node path holding the CDA |
| MIME Type | text/xml for a CDA R2 document |
| Content ID | A unique ID such as Document01. Reference this same value from the envelope |
The auto-generated envelope already includes the reference to the attachment via XOP:
<xdsb:Document id="Document01">
<xop:Include href="cid:Document01" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</xdsb:Document>
If you change the Content ID, change the href value in the envelope to match.
Step 5: Fill in the XDS.b metadata¶
On the destination node toolbar, click Meta Data to open the XDS.b Provide and Register Meta Data dialog. The dialog edits the metadata embedded in the SOAP envelope. Every field supports node-tag lookups ({PID-3}, {m:patientId}, etc.) so values can be pulled from the message at runtime.
| Group | Fields |
|---|---|
| Document descriptors | Name, Description |
| Author | Author, Author Institution, Author Role, Author Specialty |
| Identifiers | Patient ID (in the HIE's patient identifier domain), Document Source ID |
| Content Type | Value, Display Name, Scheme |
| Class Code | Value, Display Name, Scheme, high-level document class (typically LOINC) |
| Confidentiality Code | Value, Display Name, Scheme (commonly HL7 v3 Confidentiality) |
| Format Code | Value, Display Name, Scheme, the IHE/HITSP template OID identifying the document format |
| Facility Type Code | Value, Display Name, Scheme |
| Practice Setting Code | Value, Display Name, Scheme |
| Document Type Code | Value, Display Name, Scheme, specific document type (typically LOINC) |
The HIE dictates the exact coded values for each set. Most rejections during onboarding come from a code in the wrong scheme or a value the HIE's registry does not recognize.
Document Source ID across multiple facilities
If you operate multiple facilities and each must submit with its own Document Source ID, use a channel-cache or a published mapping table to look up the right OID per source location, then drop a node tag (e.g. {m:documentSourceId}) into the Document Source ID field.
Step 6: Write the ack script¶
The HIE returns HTTP 200 OK whether the submission is accepted or rejected. The actual outcome is in the SOAP body, a successful response contains <rs:RegistryResponse status="…:Success">, and a failure contains <rs:RegistryResponse status="…:Failure"> with a <rs:RegistryErrorList> carrying one or more <rs:RegistryError> entries. The destination's ack script must inspect the body to decide whether the message completes or goes to the error queue.
What the HIE sends back¶
The two response shapes look like this. The <rs:RegistryResponse> body is the same across ITI-41, ITI-42, and the ITI-18 query response, so the same ack-script pattern works for all three.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:Header>
<wsa:Action>urn:ihe:iti:2007:ProvideAndRegisterDocumentSet-bResponse</wsa:Action>
<wsa:RelatesTo>urn:uuid:...</wsa:RelatesTo>
</soapenv:Header>
<soapenv:Body>
<rs:RegistryResponse
xmlns:rs="urn:oasis:names:tc:ebxml-regrep:xsd:rs:3.0"
status="urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success"/>
</soapenv:Body>
</soapenv:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:Header>
<wsa:Action>urn:ihe:iti:2007:ProvideAndRegisterDocumentSet-bResponse</wsa:Action>
<wsa:RelatesTo>urn:uuid:...</wsa:RelatesTo>
</soapenv:Header>
<soapenv:Body>
<rs:RegistryResponse
xmlns:rs="urn:oasis:names:tc:ebxml-regrep:xsd:rs:3.0"
status="urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Failure">
<rs:RegistryErrorList>
<rs:RegistryError
codeContext="Patient Id is not known"
errorCode="XDSUnknownPatientId"
location=""
severity="urn:oasis:names:tc:ebxml-regrep:ErrorSeverityType:Error"/>
</rs:RegistryErrorList>
</rs:RegistryResponse>
</soapenv:Body>
</soapenv:Envelope>
Ack script¶
The script below maps these two shapes to QIE's success / error-queue outcomes. On the destination node, set the ack script to:
// Empty/missing response = transient failure; let QIE retry the send.
if (response == null || response.length === 0) {
qie.simulateSendError('No response received from HIE.');
}
// Any <rs:RegistryError> means the submission was rejected.
// Surface the HIE's error code and context into the error message.
if (response.indexOf('RegistryErrorList') >= 0) {
var responseXml = qie.createXMLMessage(response);
var code = responseXml.getNode('//RegistryError/@errorCode');
var context = responseXml.getNode('//RegistryError/@codeContext');
message.error('HIE rejected submission: ' + code + ' — ' + context);
return false;
}
return true;
The three behaviors:
| Outcome | Script action | Effect |
|---|---|---|
| No response | qie.simulateSendError(...) |
Treats it as if the send never happened; QIE retries per the channel's resend rules. |
| Registry rejection | message.error(...) + return false |
Message goes to the error queue with the HIE's errorCode / codeContext as the error text. |
| Success | return true |
Message marked complete; the SOAP response is stored as the response received. |
See Ack Scripts for the full ack-script return-value contract and the qie.simulateSendError / qie.throwAckError / message.error helpers.
Step 7: Test against the HIE's UAT endpoint¶
- Enter debug mode on the channel and run a test message.
- The status log records
[path=N-N] – SOAP Request:and[path=N-N] – SOAP Response:entries. Open the response to verify what the HIE sent back. - Submit the test patient/document the HIE specified for onboarding.
- Iterate on metadata values until the HIE returns a
…:Successresponse.
Typical rejection causes:
- HTTP 401 or TLS handshake failure: wrong client certificate, the HIE's trust store does not include your CA, or a TLS-version mismatch.
XDSUnknownPatientId: the patient ID is not in the HIE's patient identifier domain; run a PIX query first (ITI-9 or ITI-45) to get the HIE-side ID.XDSRegistryMetadataError: a Class Code, Format Code, or other coded value does not match what the HIE's registry expects.XDSRepositoryError: usually MTOM/XOP framing or a Content ID mismatch between the envelope and the attachment.
Companion transactions¶
ITI-41 is rarely standalone. Production HIE channels usually need one or more of these transactions, configured on the same IHE Web Service Profiles connection type:
| Step | Transaction(s) | Direction |
|---|---|---|
| Look up the HIE's patient ID | ITI-9 (PIX) or ITI-45 (PIXv3 Query) | QIE → HIE Patient ID Manager |
| Send patient demographics | ITI-8 or ITI-44 (Patient Identity Feed) | QIE → HIE PIX Manager |
| Submit the CDA | ITI-41 (Provide and Register) | QIE → HIE Repository |
| Find existing documents | ITI-18 (Adhoc Query) + ITI-43 (Retrieve) | QIE ↔ HIE Registry / Repository |
Create one IHE Web Service Connection per actor endpoint URL and check only the transactions that endpoint serves.
Replacing a previously-submitted document¶
To resubmit an updated CDA that supersedes a prior submission, the envelope must include an <rim:Association> element with associationType="urn:ihe:iti:2010:AssociationType:APND" (for an addendum) or RPLC (for a replacement), referencing the prior document's UUID. This is configured by editing the SOAP envelope directly on the SOAP Sender, typically on a second destination node alongside the first-submit destination, with the channel routing to one or the other based on a flag set in mapping. The XDS.b specification defines the full set of association semantics.