Intro · Health Samurai

HL7v2 FHIR
Building a Production Pipeline

How we went from custom one-off integrations to a reusable, testable, AI-assisted framework.

Aidbox · Atomic-EHR

Our experience

Years of HL7v2 work across tools and integrations

We've built multiple HL7v2 tools and delivered production integrations with major EHR vendors.

Built-in HL7v2 parser

Native HL7v2 message parser integrated into the Aidbox platform for receiving and parsing messages out of the box.

Built-in mappers (JUTE & Zen)

Two internal mapping engines: one built on the JUTE DSL for declarative transformations, another using Zen configuration for HL7v2-to-FHIR mapping.

External mapper (Python)

Standalone Python-based mapping service for teams that need flexibility outside the Aidbox runtime.

Production integrations

Multiple projects delivered with Epic, Cerner, and Meditech — both inbound and outbound HL7v2 messaging in production.

Challenges · Pain points

Despite years of tooling, the same walls kept coming up

Six problems that every HL7v2 integration team eventually faces.

01

Identity complexity

Patient record matching, deduplication, and identity resolution across multiple identifier systems. Different facilities assign different IDs to the same patient.

02

Source-specific variations

Different EHR systems format messages differently. Meditech and Cerner use different fields for the same clinical data like allergies, identifiers, and visit numbers.

03

Terminology mappings

Local lab codes, patient class codes, and status values need mapping to standard code systems like LOINC, SNOMED, and FHIR ValueSets. Each sender has its own local codes.

04

Operations & error handling

In production, messages fail. Teams need to see errors, understand what went wrong, fix mappings or data issues, and reprocess messages without losing anything.

05

Expensive development

Adding support for a new message type requires significant engineering effort. Each new HL7v2 event means custom parsing, mapping, and conversion logic from scratch.

06

Fragile pipeline

Difficult to test end-to-end and risky to deploy updates to production.

Solution

A queue-driven pipeline, Mapping as a code

Messages flow through a durable queue. Operations UI and Developer Workspace wrap the runtime.

Operations UI

Message queue · Mapping tasks · Error recovery

EHR Sources

MeditechCernerEpic

HL7v2 · MLLP

Work Queue

received error mapping_error

Processing Pipeline

1 Preprocessors
2 Identity
3 Code Mapping
4 Converter

Aidbox

PatientEncounterObservation

Developer Workspace

Mappings as code · Type-safe SDKs · AI agent · HL7v2 spec tool

Status-based work queues

Every message is a resource; status drives the pipeline

Messages are persisted as resources. Status transitions drive the processing pipeline end-to-end.

Status machine

received processing processed on fail error mapping_error

Introspection

Every message and its current state is visible. Query by status to see what's pending, what failed, and what succeeded.

At-least-once processing

Messages are never lost. Failed messages stay in the queue and can be retried. Mapping errors auto-requeue after resolution.

Mappings as code

HL7v2-to-FHIR conversion lives in TypeScript — not in a black box

  • Manual field indexing

    Use the $N_fieldName pattern (e.g., pid.$5_name).

  • Full IDE autocomplete

    Available at every nesting level.

  • Testing

    Unit and integration tests for every message type.

  • Governance

    Code review and version control for mapping changes.

v2-to-fhir/segments/pid-patient.ts
export function convertPIDToPatient(
  pid: PID,
  policy: PatientConversionPolicy = DEFAULT_PATIENT_CONVERSION_POLICY,
): Patient {
  const patient: Patient = { resourceType: "Patient" };

  // PID-3: Patient Identifier List
  patient.identifier = pid.$3_identifier
    ?.map(convertCXToIdentifier)
    .filter(Boolean);

  // PID-5: Patient Name
  patient.name = pid.$5_name
    ?.map(convertXPNToHumanName)
    .filter(Boolean);

  // PID-7: Date of Birth
  if (pid.$7_birthDate) {
    patient.birthDate = convertDTMToDate(pid.$7_birthDate);
  }

  // PID-8: Administrative Sex
  if (pid.$8_gender) {
    patient.gender = GENDER_MAP[pid.$8_gender.toUpperCase()];
  }

  return patient;
}

SDKs · HL7v2 & FHIR

Type-safe SDKs eliminate entire categories of runtime errors

Two packages cover both sides of the wire: HL7v2 segments on input, FHIR resources on output.

HL7v2 @atomic-ehr/hl7v2

Typed HL7v2 parser with generated types for every segment, field, and component. Access PID-3, OBX-5, or MSH-9 with full autocomplete.

Read a field

msg.pid.$5_familyName
FHIR R4 @atomic-ehr/codegen

Generate FHIR R4 TypeScript types from the spec. Build Patient, Observation, and Bundle resources with compile-time validation.

Build a resource

Patient.name[0]

Source preprocessors

Normalize sender-specific quirks before conversion runs

Handle EHR-specific message variations before they reach the conversion logic.

How it works

Each message type declares which preprocessors to run in the config file. Preprocessors normalize sender-specific quirks so converters only deal with clean, consistent data.

Examples

  • Meditech patient ID in PID-2 instead of PID-3
  • Some senders omit the authority in PV1-19
  • Vaccine doses come in inconsistent formats

Each gets a small, testable preprocessor.

Operations UI

Manage the full message lifecycle in production

A built-in web interface covers queue inspection, mapping resolution, and error recovery.

01

Message queue

Filter by status, sender, message type. Inspect raw HL7v2 and resulting FHIR resources.

02

Mapping tasks

Resolve unmapped local codes to LOINC / SNOMED. Messages auto-reprocess after resolution.

03

Error recovery

View error details, fix the root cause, one-click retry without data loss.

AI-friendly

Structured for AI-assisted development from day one

New message type

From a day of engineering to a guided conversation.

  • AGENTS.md

    Describes the project architecture for AI assistants.

  • Custom skills

    For common tasks like adding message types or creating preprocessors.

  • HL7v2 spec tool

    Lets AI deeply understand different versions of the HL7v2 format.

Developer workspace

Write, test, and deploy mappings in one place

01

AI agent

Reads AGENTS.md, understands project structure, generates converters and tests.

02

HL7v2 spec tool

AI looks up segment definitions, field types, and version differences on demand.

03

Type-safe SDKs

Autocomplete for HL7v2 segments and FHIR resources; catch errors at compile time.

04

Tests

AI runs tests to validate its own changes before submitting.

Demo

See it running

The full pipeline, operations UI, and developer workspace — ready to explore.

Recommended path

Two ways we take this to production with you

1

License · Software

Interbox

Our new high-performance workflow engine. Drop the HL7v2 pipeline into Interbox to run it as a durable, observable workflow alongside the rest of your integrations.

Learn more

2

Engagement · With our team

Bootstrap project

Our engineers work alongside yours to adopt the pipeline — converters for your message types, EHR wiring, operations handoff. You ship faster, your team owns it after.

Together: a production HL7v2 → FHIR pipeline in weeks, not quarters.

1 / 13