HL7v2 to FHIR - what you get per message

The FHIR resources produced for ADT, ORU, ORM, SIU, VXU and MDM messages, and the segments each resource comes from.

An HL7v2 message is one flat list of segments, while FHIR splits the same information into separate resources - the patient in PID becomes a Patient, the visit in PV1 an Encounter, each OBX result an Observation. The tables below spell that mapping out, segment by segment and message family by message family.

What a converted bundle contains follows the segments actually present in the message, not a fixed list per message type. Alongside the clinical resources, the sending and receiving facilities from MSH-4 and MSH-6 become Organization resources referenced from the MessageHeader, so every bundle opens with them.

Segments and their resources

SegmentFHIR resourceNotes
MSHMessageHeaderEvent coding from MSH-9, source and destination endpoints, focus points at the Patient, the MSH-4 and MSH-6 facilities become Organization resources referenced as sender and receiver
PIDPatientIdentifiers, names, birth date, gender, addresses, telecoms, language, marital status, birth place, multiple-birth and deceased indicators
PD1-Enriches the Patient - organizations and practitioners become generalPractitioner
NK1RelatedPersonOne per NK1 - name, relationship, address, telecom
PV1EncounterClass, status, locations, attending, referring, consulting and admitting practitioners, service type, admit source, visit number, period
PV2-Enriches the Encounter - admit reason becomes reasonCode
OBXObservationValue typing follows OBX-2, see below
AL1AllergyIntoleranceOne per AL1 - code, category, type, criticality, severity, reactions
DG1ConditionOne per DG1, also appended to Encounter.diagnosis with its use and rank
PR1ProcedureOne per PR1
IN1CoverageOne per IN1, plus the payor Organization
ORC and OBRServiceRequestOne per order group in order and result messages
OBRDiagnosticReportIn result messages, one per OBR, linked basedOn its ServiceRequest
NTE-Becomes a note on the resource it follows - an Observation, a ServiceRequest or an Appointment
SPMSpecimenOne per SPM, appended to the current report's specimen
SCHAppointmentIn scheduling messages
AIS, AIG, AIL, AIP-Enrich the Appointment - service type and participants, with Location and Practitioner resources where applicable
RXAImmunizationIn immunization messages - vaccine code, occurrence, dose, performer, lot number, manufacturer Organization
RXR-Enriches the Immunization - route and site
TXADocumentReferenceIn document messages, body gathered from the text OBX segments that follow
Z-segmentsBasicPreserved as extensions

Repeating segments become multiple resources - three NK1 segments produce three RelatedPerson resources, five OBX segments five Observations, and so on.

Practitioner, Location and Organization resources are created on demand when a field references one, e.g. the attending doctor in PV1-7 or the assigned location in PV1-3, and identical entities are deduplicated across the whole bundle.

Message families

The message structure from MSH-9 selects a conversion family, which determines how order-related segments group together:

FamilyMessage structuresAdds on top of the common segments
Admissions and the restADT and everything not listed belowNothing - the common segments alone
OrdersORM, OML, OMGServiceRequest per ORC/OBR group
ResultsORUServiceRequest and DiagnosticReport per group, with Observations in result and Specimens in specimen
SchedulingSIUAppointment with participants
ImmunizationsVXUImmunization per RXA
DocumentsMDMDocumentReference from TXA and the text OBX body

An ORU^R01 example

from zato.hl7v2 import parse_hl7

raw = (
    'MSH|^~\\&|LAB|FACILITY|EHR|FAC|20260315101112||ORU^R01^ORU_R01|CTL002|P|2.9\r'
    'PID|||12345^^^HOSP^MR||SMITH^JOHN^A||19800115|M\r'
    'ORC|RE|PLACER001|FILLER001\r'
    'OBR|1|PLACER001|FILLER001|24331-1^Lipid panel^LN|||202603150930|||||||||||||||||F\r'
    'OBX|1|NM|2093-3^Cholesterol^LN||187|mg/dL^^UCUM|<200|N|||F\r'
    'NTE|1||Fasting sample\r'
    'OBX|2|NM|2085-9^HDL cholesterol^LN||62|mg/dL^^UCUM|>40|N|||F\r'
    'OBX|3|NM|2571-8^Triglycerides^LN||145|mg/dL^^UCUM|<150|N|||F\r'
    'SPM|1|SPM001||SER^Serum\r'
)

msg = parse_hl7(raw, validate=False)
bundle = msg.to_fhir()

for entry in bundle.entry:
    print(entry.resource.resource_type)
Organization
Organization
MessageHeader
Patient
ServiceRequest
DiagnosticReport
Observation
Observation
Observation
Specimen

Each Observation has a valueQuantity - 187, 62 and 145 mg/dL - and the NTE comment is stored in the first one's note. The DiagnosticReport lists all three Observations in result and the Specimen in specimen, and everything points back at the Patient.

Observation values

The OBX-2 value type determines how OBX-5 is represented:

OBX-2FHIR element
NMvalueQuantity, with units from OBX-6
ST, TX, FTvalueString
CE, CWE, CNE, CF, ISvalueCodeableConcept
SNvalueQuantity, valueRange or valueRatio, depending on the structured numeric
DT, DTM, TSvalueDateTime
TMvalueTime

A value type outside this table falls back to valueString, so the value stays in the output.

See also

PageWhat it covers
Automatic conversionOne call, a complete MLLP-to-FHIR service and validation
References and deduplicationHow the resources point at each other and identical entities merge
Customizing code mappingsStandard tables, local values and unknown codes
Z-segmentsCustom segments preserved as Basic resources with extensions

Learn more


Schedule a meaningful demo

Book a demo with an expert who will help you build meaningful systems that match your ambitions

"We evaluated 12 integration platforms and Zato was the only one to score 100%."

Philip Zuñiga, Assistant Professor, University of the Philippines