Skip to content
LambogeniusDocs

HL7 MLLP Connector for Azure Logic Apps

Gateway reference

Gateway configuration, the request it posts to your workflow, ACK mapping, and its HTTP API.

Service provider/serviceProviders/lamboHl7MllpLicensed together with the HL7 v2 Codec. One token covers both.

Configuration

The Gateway section of appsettings.json, or environment variables (: becomes __). Keep secrets such as API keys, trigger URLs and certificates in Key Vault or environment variables, never in the file.

{
  "Gateway": {
    "ApiKeys": [],                       // from secrets: Gateway__ApiKeys__0
    "RequireTls": false,
    "AllowedDestinations": [ "emr.hospital.internal:2575", "10.20.*:*" ],
    "Listeners": [
      {
        "Name": "adt",
        "Port": 2575,
        "BindAddress": "0.0.0.0",
        "Encoding": "utf-8",             // or "auto" to use MSH-18
        "AcknowledgementMode": "Auto",   // Auto | Workflow | None
        "AcknowledgementType": "Original",
        "BatchMode": "Split",            // Split | Single | Reject
        "ResponseTimeoutSeconds": 60,
        "TimeoutBehavior": "SendNegativeAck",
        "TargetUrl": "",                 // from secrets: Gateway__Listeners__0__TargetUrl
        "HttpRetryCount": 2,
        "Archive": false,
        "Tls": { "Enabled": false, "Version": "1.2", "Certificate": "", "RequireClientCertificate": false }
      }
    ]
  }
}

What the workflow receives

A POST with this JSON body, plus the headers X-MLLP-Message-Control-Id, X-MLLP-Connection-Id and X-MLLP-Message-Id (and X-MLLP-Batch-Control-Id for batches). The built-in trigger's outputs have the same fields.

{
  "message": "MSH|^~\&|LAB|HOSP|EHR|HOSP|20261016093000||ADT^A01^ADT_A01|MSG00001|P|2.5.1\rPID|...",
  "messageId": "…", "contextId": "…", "connectionId": "…", "sequenceNumber": 1,
  "remoteEndpoint": "10.1.2.3:51234", "localEndpoint": "10.80.0.4:2575",
  "receivedAt": "2026-10-16T09:30:00.0000000+00:00", "encoding": "utf-8",
  "isValid": true, "validationError": null,
  "messageControlId": "MSG00001", "messageType": "ADT^A01^ADT_A01", "messageCode": "ADT",
  "triggerEvent": "A01", "messageStructure": "ADT_A01",
  "sendingApplication": "LAB", "sendingFacility": "HOSP", "receivingApplication": "EHR", "receivingFacility": "HOSP",
  "messageDateTime": "20261016093000", "processingId": "P", "versionId": "2.5.1",
  "acceptAckType": "", "applicationAckType": "", "applicationAckRequested": true, "characterSet": "",
  "isBatch": false, "tlsProtocol": null, "clientCertificateSubject": null, "clientCertificateThumbprint": null,
  "archiveId": null
}

How the response becomes the ACK

Workflow responseAuto modeWorkflow mode
2xxAA (CA in enhanced mode)The body is the ACK: plain HL7, a JSON string, or {"acknowledgement": "…"}
400 or 422AR / CRAR / CR
5xx, 429, network errorRetried (HttpRetryCount, default 2, with backoff), then AE / CEAE / CE, not retried, so a message never starts two runs
No response in timeAE / CETimeoutBehavior: SendNegativeAck, CloseConnection or NoResponse

HTTP API

POST /api/v1/messages/send and POST /api/v1/acknowledgements back the custom connector used by Consumption Logic Apps. Both require an x-api-key, and the send API only connects to destinations listed in AllowedDestinations, so the gateway can't be used as an open relay. Client certificates are referenced by name from Gateway:ClientCertificates, so certificate material never travels in a request.

curl -X POST https://<gateway-fqdn>/api/v1/messages/send \
  -H "x-api-key: <key>" -H "Content-Type: application/json" \
  -d '{
    "host": "emr.hospital.internal", "port": 2575,
    "message": "MSH|^~\\&|LAB|HOSP|EMR|HOSP|20261016093000||ORU^R01^ORU_R01|MSG00042|P|2.5.1\rPID|...",
    "waitForAck": true, "keepConnectionOpen": true, "failOnNegativeAck": true,
    "useTls": true, "tlsTrustedServerThumbprints": [ "<sha-256 thumbprint>" ], "tlsClientCertificate": "emr"
  }'

Health

GET /healthz on port 8080 reports each listener's state, including why a listener didn't start (for example a plain listener when TLS is required).