Skip to content

Vendor profiles

A vendor profile bundles everything subscription-service needs to talk to one EHR vendor’s HL7 v2 (or proprietary REST) feed: message mappings, vendor-specific quirks, audit-event enrichments, sample messages, and a regression-test suite. A profile is a .tgz drop-in — install one and the engine just works against that vendor.

Where profiles live

The canonical, community-maintained catalog of profiles is the subscription-service-profiles repo. Each profile lives in its own directory:

subscription-service-profiles/
├── epic/
├── meditech/
├── cerner/
├── athena/
└── _template/

Two flavors ship today:

  • Community profiles (Apache 2.0) — best-effort, contributed by integrators, maintained on a best-effort cadence
  • Certified profiles (commercial) — the same shape, plus a signed regression-test report, indemnity statement, and an upgrade SLA

A non-commercial deployment can ship to production using a community profile; the difference is who’s on the hook when an EHR vendor changes a quirk.

What a profile contains

profiles/epic/
├── manifest.yaml # profile metadata + ingest + mappings + quirks + audit
├── maps/ # FHIR Mapping Language (.fml) StructureMaps
│ ├── hl7v2-ADT-A04-Epic.fml
│ ├── hl7v2-ORM-O01-Epic.fml
│ └── hl7v2-ORU-R01-Epic.fml
├── tests/ # positive + negative regression tests
│ ├── adt-a04/
│ ├── orm-o01/
│ └── oru-r01/
└── README.md # human-readable: what versions, what quirks, support contact

The manifest.yaml shape is documented in detail in the engine repo’s architecture doc under “Profile manifest.” A minimal Epic profile:

profile:
id: epic
version: 2024.1
schemaVersion: 1
vendor:
name: Epic Systems
productLine: Epic
productVersion: "2024.x"
fhirVersions: [R4]
hl7Versions: [v2.5, v2.5.1, v2.7]
ingest:
- id: mllp-default
type: hl7v2-mllp
port: 2575
facilityResolver: epic-msh-3-facility
mappings:
- messageType: ADT^A04
map: maps/hl7v2-ADT-A04-Epic.fml
tests: [tests/adt-a04/]
quirks:
msh3-format: facility-shortcode-then-pipe
empty-pid-strategy: synthesize-from-mrn
attachment-encoding: base64-with-rtf-prefix-trim
audit:
agent-system: epic
enrichments:
- addOriginatingUser: pv1.7
- addPatientFacility: msh.4

Every quirks and audit key corresponds to a hook the engine recognizes — unknown keys fail the load with a clear error. Add new quirk strategies via a built-in plugin contribution or a side-car JAR.

Non-HL7 profiles

Profiles aren’t limited to MLLP. The ingest block is a typed list; for a vendor like Athena that exposes REST APIs (some FHIR R4, some proprietary), a profile mixes:

  • athena-native-rest — proprietary polling client (OAuth2 client-credentials, polls for changedPatients, changedAppointments, etc.)
  • fhir-r4-polling — generic FHIR R4 search polling for the standardized surface

The mapping step for FHIR-source profiles is a normalization (apply US Core slices, strip vendor extensions, stamp provenance) rather than an HL7 transform.

Installing a profile

Terminal window
# Drop the .tgz into the engine's plugin directory
cp epic-2024.1.tgz /var/subscription-service/plugins/profiles/
# Validate (without restarting)
curl -X POST https://your-host/admin/api/profiles/validate \
-H "Content-Type: application/x-gtar" \
--data-binary @epic-2024.1.tgz
# Restart the engine to load
systemctl restart subscription-service

The admin API also supports zero-downtime reload via POST /admin/api/profiles/reload (Pro tier).

Authoring your own

Start from the _template directory in the profiles repo:

  1. cp -r _template/ myvendor/
  2. Edit manifest.yaml to declare your vendor + supported message types
  3. Author one StructureMap per message type in maps/
  4. Add representative positive + negative sample messages to tests/
  5. Run the engine’s profile-test harness: ./gradlew testProfile -Pprofile=myvendor
  6. When all tests pass: package with ./gradlew packageProfile -Pprofile=myvendordist/myvendor-1.0.0.tgz
  7. Submit a PR to the catalog repo, or ship the .tgz privately

The harness boots the engine against an in-memory HAPI, feeds your sample messages through the configured ingest, applies your maps, and asserts the resulting Bundles match the golden FHIR fixtures under tests/. The same harness runs in CI on every PR to the profiles repo.

When to author vs. wait

If your vendor is in the catalog with a recent profile.version, use it as-is. If the catalog has an older version or your facility uses a non-standard variant (custom MSH-3 format, an in-house OBX-5 convention), fork the existing profile and submit a PR with your delta — vendor profiles are designed to absorb minor facility-specific drift via the quirks block without per-facility forks.