This guide explains how to verify TransTrack's hospital integration end-to-end and how to wire it into the major US EHRs (Epic, Cerner/Oracle Health, Meditech, Allscripts/Veradigm, athenahealth, NextGen, eClinicalWorks).
┌─────────────────┐ MLLP/TLS ┌──────────────────────┐
│ Hospital engine │ ─────────────────────▶ │ TransTrack listener │
│ (Mirth/Rhapsody│ ◀─────────── MSA|AA │ :2575 │
│ Cloverleaf) │ └──────────────────────┘
└─────────────────┘
│ ┌──────────────────────┐
│ FHIR R4 (REST/HTTPS) │ TransTrack /fhir/... │
└──────────────────────────────────────▶│ /oauth2/... │
│ /cds-services/... │
└──────────────────────┘
Real production deployments wrap MLLP in TLS with mutual cert auth.
For local testing we use plaintext MLLP for simplicity, but the
production code path is the same — just set
HL7_MLLP_TLS_CERT_FILE / HL7_MLLP_TLS_KEY_FILE.
| Capability | Spec / version | Status |
|---|---|---|
| MLLP framing | HL7 MLLP transport | ✓ |
| MLLP over TLS (mutual auth optional) | RFC 5246+ | ✓ |
| HL7 v2.5 ADT (A01, A03, A04, A08, A11, | ||
| A13, A28, A31, A40 merge, A60) | HL7 v2.5 | ✓ |
| HL7 v2.5 ORU^R01, ORU^R30 | HL7 v2.5 | ✓ |
| HL7 v2.5 ORM^O01, OMP^O09 | HL7 v2.5 | ✓ |
| HL7 v2.5 RDE^O11, RDS^O13 | HL7 v2.5 | ✓ |
| HL7 v2.5 MDM^T01, MDM^T02 | HL7 v2.5 | ✓ |
| HL7 v2.5 SIU^S12 / S13 / S14 / S15 / S26 | HL7 v2.5 | capture-only |
| HL7 v2.5 BAR^P01-P05, DFT^P03 / P11 | HL7 v2.5 | capture-only |
| HL7 v2.5 MFN^M02 / M05 / M06 | HL7 v2.5 | capture-only |
| Z-segment extensibility (Epic, Cerner, | ||
| Meditech baked in; per-org config for the | ||
| rest) | n/a | ✓ |
| MSA acknowledgement (AA / AE / AR) | HL7 v2.5 | ✓ |
| FHIR R4 CapabilityStatement | FHIR R4 | ✓ |
| FHIR R4 USCDI v3 resources (Patient, | ||
| Encounter, Condition, Observation, | ||
| MedicationRequest, MedicationStatement, | ||
| AllergyIntolerance, DocumentReference, | ||
| DiagnosticReport, Immunization, | ||
| Procedure, CarePlan, CareTeam, Goal, | ||
| Coverage, Organization, Practitioner, | ||
| PractitionerRole, Location, Device, | ||
| Provenance, Subscription) | USCDI v3 | ✓ |
| FHIR R4 Bundle transaction | FHIR R4 | ✓ |
| FHIR Bulk Data Access ($export NDJSON) | FHIR Bulk Data 1.0 | ✓ |
| FHIR R4 Subscription (REST-hook delivery) | FHIR R4 | ✓ |
| SMART on FHIR v2 (authorize, token, | ||
| introspect, revoke, dynamic registration, | ||
| PKCE, refresh, launch context) | SMART App Launch v2 | ✓ |
| SMART Backend Services (client_credentials | ||
| + JWT bearer assertion) | SMART Backend Services | ✓ |
| CDS Hooks 1.1 (discovery + invocation + | ||
| feedback) | CDS Hooks 1.1 | ✓ |
| CCD / CCDA import | CCDA R2.1 | TODO |
| OPO DonorNet (UNOS UNet) connector | proprietary | TODO |
The unit tests cover the framer + parsers. The integration tests cover the full ingest path (TCP → MLLP → parse → DB → ack) and the FHIR surface:
cd server
docker compose -f ../docker/docker-compose.yml up -d postgres
npm install
npm run migrate
npm run test:integrationThe end-to-end smoke test exercises every integration surface in one shot (HL7 + FHIR + SMART + CDS Hooks + Bulk Data):
npm run smoke # from repo root, brings up postgres+api, runs the suiteTCP :2575 # plaintext (dev)
TCP :2576 # TLS (set HL7_MLLP_TLS_*)
GET /fhir/metadata
GET /fhir/{Type} # search
GET /fhir/{Type}/{id} # read
GET /fhir/{Type}/{id}/_history # history
POST /fhir/{Type} # create
PUT /fhir/{Type}/{id} # update
DELETE /fhir/{Type}/{id} # soft delete
POST /fhir # transaction Bundle
POST /fhir/$export # Bulk Data system export
POST /fhir/Patient/$export # Bulk Data patient compartment
POST /fhir/Group/{id}/$export # Bulk Data group export
GET /fhir/$export-status/{jobId} # poll Bulk Data
GET /fhir/$export-file/{fileId} # NDJSON file
DELETE /fhir/$export-status/{jobId} # cancel
GET /.well-known/smart-configuration
GET /fhir/.well-known/smart-configuration
GET /oauth2/authorize
POST /oauth2/authorize
POST /oauth2/token
POST /oauth2/register # RFC 7591 dynamic client registration
GET /oauth2/clients # admin
POST /oauth2/introspect # RFC 7662
POST /oauth2/revoke # RFC 7009
Supported grants: authorization_code (+ PKCE), refresh_token,
client_credentials, urn:ietf:params:oauth:grant-type:jwt-bearer.
Scopes are fully v1 (patient/Patient.read) and v2 (patient/Patient.rs)
syntax-aware and enforced on every FHIR call.
GET /cds-services
POST /cds-services/{id}
POST /cds-services/{id}/feedback
Built-in services (more can be registered via
require('./cds/registry').register(...)):
transplant-candidate-summary— patient-view banner with active candidacy status, blood type, last creatinine.nephrotoxic-medication-advisory— order-select alert when an EHR user prescribes an NSAID/aminoglycoside/etc. to a kidney candidate.hla-screening-reminder— order-sign reminder if HLA antibody screening is overdue (>30 days for active candidates).
- Register the deployment's FHIR base +
/.well-known/smart-configurationin App Orchard. Use SMART v2 scopes. - For backend services (population health pulls, scheduled exports)
register a JWKS URL pointing at your public keys; TransTrack accepts
the
jwt-bearergrant. - HL7: Epic Bridges sends Z-segments
ZPD,ZPV,ZID,ZTXby default. The Epic vendor profile (/hl7/vendor-profiles/seed-defaults) maps these to candidate flags, encounter context, identifiers, and transplant text fields. - Bulk Data: Epic supports
_typeFilterand_since; both are honored.
- Same SMART app registration model. Cerner supports both v1 and v2 scope syntax — TransTrack accepts either.
- HL7: Cerner OpenEngine emits
ZPI,ZPV, and ORUZRXfor med reconciliation; the Cerner profile resolves them. - Cerner's Bulk Data implementation only supports
PatientandGroupexports, which mirrors TransTrack's surface.
- SMART on FHIR launched apps are supported via Meditech Greenfield.
Set the
audclaim to your TransTrack FHIR base. - HL7: Meditech DR sends
ZFSfinancial segments andZTXfreetext; resolved by the Meditech vendor profile.
- Sunrise IIE relays MLLP over TLS — point it at TransTrack:2576.
- Vendor profile
allscriptscoversZALallergies +ZINinsurance.
- FHIR-only (no inbound HL7 in their Cloud product).
- SMART app registration via
marketplace.athenahealth.com. - CDS Hooks: register the discovery URL in MDP.
- Both ship with Mirth Connect — use the channels in
docker/mirth/as a starting template. - Both vendor profiles handle their
Z*extensions.
POST /hl7/vendor-profiles/seed-defaults
GET /hl7/vendor-profiles
POST /hl7/vendor-profiles
PUT /hl7/vendor-profiles/:id
DELETE /hl7/vendor-profiles/:id
GET /hl7/supported-types
GET /hl7/messages?limit=...
Each profile is JSON; schema:
# 1. Start everything
cd docker
docker compose up -d postgres api mirth
# 2. Apply DB migrations
docker compose exec api node src/db/migrate.js up
# 3. Open the Mirth Administrator
open https://localhost:8443
# default credentials: admin / admin (change after first login)
# 4. Import the channels in docker/mirth/channels/
# Mirth → Channels → Import Channel → select transtrack-relay.xml
# and transtrack-file-in.xml
# Deploy both.
# 5. Drop a sample HL7 file into the file-watch directory
cat > docker/mirth/inbox/sample-adt.hl7 <<'EOF'
MSH|^~\&|EPIC|HOSP|TT|TT|20260101120000||ADT^A04|MIRTH-001|P|2.5
EVN|A04|20260101120000
PID|1||MIRTH-MRN-1^^^HOSP^MR||DOE^JANE||19800101|F
EOF
# 6. Within ~5 seconds Mirth picks up the file and forwards it.
# Verify on the TransTrack side:
curl -H "Authorization: Bearer <token>" \
http://localhost:8080/hl7/messages?limit=10 | jq
# 7. Optional: run the harness test that automates steps 5-6
INTEGRATION_MIRTH=1 npm --prefix server run test:mirth# Discovery
curl http://localhost:8080/.well-known/smart-configuration | jq
# Register a backend client (admin token required)
curl -XPOST http://localhost:8080/oauth2/register \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{
"client_name": "PopHealth",
"grant_types": ["client_credentials"],
"scope": "system/Patient.rs system/Observation.rs"
}' | jq
# Get an access token
curl -XPOST http://localhost:8080/oauth2/token \
-d "grant_type=client_credentials" \
-d "client_id=$ID" \
-d "client_secret=$SECRET" \
-d "scope=system/Patient.rs"
# Use the token
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/fhir/Patient# Kick off
curl -XPOST http://localhost:8080/fhir/Patient/\$export \
-H "Authorization: Bearer $TOKEN" \
-H "Prefer: respond-async" \
-H "Accept: application/fhir+json" -i
# Poll the Content-Location URL until 200
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/fhir/\$export-status/$JOB_ID
# Download NDJSON files from the manifest
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/fhir/\$export-file/$FILE_ID# Discovery
curl http://localhost:8080/cds-services | jq
# Invoke
curl -XPOST http://localhost:8080/cds-services/transplant-candidate-summary \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"hookInstance": "abc",
"hook": "patient-view",
"context": { "patientId": "Patient/123", "userId": "Practitioner/9" }
}' | jq
{ "name": "epic-ce", "vendor": "epic", "sending_application": "EPIC", "z_segments": { "ZPD": { "fields": [ "ssn", "race", "ethnicity", "preferred_language", "religion", "transplant_candidate_flag" ] } }, "field_overrides": { "PID-19": "social_security_number" } }