Healthcare Integration-11 min read

HL7 v2 message types with sample messages: ADT, ORM, ORU, SIU, MDM, DFT and ACK

A field-level reference for HL7 v2 messages: how MSH-9 and the delimiters work, one annotated synthetic sample per common message type, and the pitfalls that break interfaces in production.

Ala Ben Aicha

HL7 v2 message types with sample messages: ADT, ORM, ORU, SIU, MDM, DFT and ACK

Direct answer

An HL7 v2 message is a stack of segments (MSH, PID, PV1, OBR, OBX...), one per line, with fields split by | and components by ^. MSH-9 names the message: type, trigger event and structure, for example ADT^A01^ADT_A01. The types you meet in almost every hospital are ADT (patient movements), ORM or OML (orders), ORU (results), SIU (scheduling), MDM (documents), DFT (charges) and ACK (acknowledgments). Every sample below is synthetic and uses v2.5.1 field positions unless stated otherwise.

How a v2 message is built

The rules live in Chapter 2 of the standard (HL7 v2.5.1 Control chapter). Field numbers in this article were checked against the v2.5.1 segment definitions (Caristix HL7 v2.5.1 reference).

A message starts with MSH|^~\&|. The character right after "MSH" is the field separator, and it is also the value of MSH-1. The next four characters are MSH-2, the encoding characters, in fixed order:

  • | field separator
  • ^ component separator
  • ~ repetition separator
  • \ escape character
  • & subcomponent separator

Segments end with a carriage return (hex 0D), written \r in most code. Not a line feed. Files saved on Windows or Linux often carry \r\n or \n, and engines normalise them on read. On the network, v2 usually travels over MLLP: each message is wrapped in a 0x0B start byte and a 0x1C 0x0D trailer over a plain TCP socket.

MSH-9 (data type MSG) has three components since v2.3.1: message code (table 0076), trigger event (table 0003) and message structure. The structure tells a parser which segment grammar to apply. A04 and A08 do not have their own grammar; they reuse ADT_A01, as HL7 table 0354 shows.

MSH field Name Sample value Notes
MSH-3 / MSH-4 Sending application / facility ADTSYS / GENHOSP Routing key in most engines
MSH-5 / MSH-6 Receiving application / facility ENGINE / GENHOSP Often ignored by receivers, still worth setting
MSH-7 Date/time of message 20261006142800+0200 TS; add the UTC offset
MSH-9 Message type ADT^A01^ADT_A01 Code, trigger, structure
MSH-10 Message control ID MSG00001 Unique per sender; echoed in MSA-2
MSH-11 Processing ID P P production, T training, D debugging
MSH-12 Version ID 2.5.1 Drives field meaning, see pitfalls
MSH-15 / MSH-16 Accept / application ack type AL / NE Enhanced acknowledgment mode only
MSH-18 Character set UNICODE UTF-8 Often left empty; agree on it explicitly

Counting trap: when you split MSH on |, array index 1 holds MSH-2, not MSH-1, because the first separator is itself MSH-1. Every other segment counts normally.

ADT messages: A01, A04, A08, A03

ADT carries patient administration events from the registration or ADT system to everyone else. The four you will see most:

ADT^A01, admit. For admitted inpatients assigned to a bed. Starts the stay.

MSH|^~\&|ADTSYS|GENHOSP|ENGINE|GENHOSP|20261006142800+0200||ADT^A01^ADT_A01|MSG00001|P|2.5.1
EVN|A01|20261006142800+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR~P900001^^^REGION&2.16.840.1.113883.19.6&ISO^PI||DOE^JANE^M^^^^L||19840312|F|||12 SAMPLE ST^^SPRINGFIELD^^10001^USA^H||^PRN^PH^^1^555^0100123|||||ACC77001^^^GENHOSP^AN
PV1|1|I|4WEST^412^B^GENHOSP|U|||1001^MARTIN^CLAIRE^^^DR|||MED||||7|||1001^MARTIN^CLAIRE^^^DR||V000456^^^GENHOSP^VN|||||||||||||||||||||||||20261006142500+0200

ADT^A04, register. An outpatient or emergency registration with no bed. Note PV1-2 = O and the structure ADT^A04^ADT_A01.

MSH|^~\&|ADTSYS|GENHOSP|ENGINE|GENHOSP|20261006090500+0200||ADT^A04^ADT_A01|MSG00002|P|2.5.1
EVN|A04|20261006090500+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|O|CARDCLIN^^^GENHOSP||||1001^MARTIN^CLAIRE^^^DR|||CAR|||||||||V000457^^^GENHOSP^VN|||||||||||||||||||||||||20261006090000+0200

ADT^A08, update patient information. Used when patient data changes and no more specific trigger applies (an address change here). It is not a new visit.

MSH|^~\&|ADTSYS|GENHOSP|ENGINE|GENHOSP|20261007111500+0200||ADT^A08^ADT_A01|MSG00003|P|2.5.1
EVN|A08|20261007111500+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F|||48 EXAMPLE AVE^APT 3^SPRINGFIELD^^10002^USA^H
PV1|1|I|4WEST^412^B^GENHOSP||||1001^MARTIN^CLAIRE^^^DR|||MED|||||||||V000456^^^GENHOSP^VN

ADT^A03, discharge. Ends the visit. PV1-36 carries the discharge disposition and PV1-45 the discharge time.

MSH|^~\&|ADTSYS|GENHOSP|ENGINE|GENHOSP|20261009160000+0200||ADT^A03^ADT_A03|MSG00004|P|2.5.1
EVN|A03|20261009160000+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||1001^MARTIN^CLAIRE^^^DR|||MED|||||||||V000456^^^GENHOSP^VN|||||||||||||||||01||||||||20261006142500+0200|20261009154500+0200

Key PID fields:

Field Name In the sample
PID-3 Patient identifier list (CX, repeating) MRN with assigning authority GENHOSP, then a regional ID
PID-5 Patient name (XPN) DOE^JANE^M, name type L (legal)
PID-7 Date/time of birth 19840312
PID-8 Administrative sex (table 0001) F
PID-11 Patient address (XAD) Street^other^city^state^zip^country^type
PID-13 Home phone (XTN) Use code PRN, equipment PH
PID-18 Patient account number ACC77001
PID-29 / PID-30 Death date/time, death indicator Empty here

Key PV1 fields:

Field Name In the sample
PV1-2 Patient class (table 0004) I inpatient, O outpatient, E emergency
PV1-3 Assigned patient location (PL) Point of care^room^bed^facility
PV1-7 / PV1-17 Attending / admitting doctor 1001^MARTIN^CLAIRE
PV1-10 Hospital service MED
PV1-19 Visit number V000456, type VN
PV1-36 Discharge disposition 01, home or self care
PV1-44 / PV1-45 Admit / discharge date/time Start and end of the visit

Other ADT triggers from table 0003 that show up in real feeds:

Trigger Meaning What the receiver usually does
A02 Transfer a patient Move bed or unit, same visit
A05 Pre-admit Create a planned visit
A06 / A07 Outpatient to inpatient / inpatient to outpatient Change patient class on the visit
A11 / A12 / A13 Cancel admit / transfer / discharge Undo the earlier event
A28 / A31 Add / update person information Master patient data with no visit
A40 Merge patient, identifier list Merge two identities, see the MPI article

How these map onto FHIR Patient and Encounter is covered in the ADT to FHIR mapping guide.

Orders: ORM^O01 and OML^O21

ORM^O01 is the general order message most lab and radiology interfaces were built on. From v2.4 it is retained for backward compatibility only, and HL7 now lists ORM_O01 as deprecated in table 0354. The replacements are specific: OML^O21 for lab, OMI^O23 for imaging, OMG^O19 for general clinical orders, OMP^O09 for pharmacy. In practice plenty of production interfaces still send ORM, so check what the receiving LIS or RIS actually accepts before you pick.

MSH|^~\&|CPOE|GENHOSP|LIS|GENLAB|20261006150000+0200||ORM^O01^ORM_O01|MSG00010|P|2.4
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||||||||||||||V000456^^^GENHOSP^VN
ORC|NW|ORD448811^CPOE|||||||20261006150000+0200|||1001^MARTIN^CLAIRE^^^DR
OBR|1|ORD448811^CPOE||24321-2^Basic metabolic 2000 panel - Serum or Plasma^LN||||||||||||1001^MARTIN^CLAIRE^^^DR

The same order as OML^O21 in v2.5.1, with timing moved to a TQ1 segment:

MSH|^~\&|CPOE|GENHOSP|LIS|GENLAB|20261006150000+0200||OML^O21^OML_O21|MSG00011|P|2.5.1
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||||||||||||||V000456^^^GENHOSP^VN
ORC|NW|ORD448811^CPOE|||||||20261006150000+0200|||1001^MARTIN^CLAIRE^^^DR
TQ1|1||||||20261006150000+0200||R^Routine^HL70485
OBR|1|ORD448811^CPOE||24321-2^Basic metabolic 2000 panel - Serum or Plasma^LN||||||||||||1001^MARTIN^CLAIRE^^^DR
Field Name Notes
ORC-1 Order control (table 0119) NW new, CA cancel request, XO change, RE results to follow
ORC-2 / OBR-2 Placer order number Assigned by the ordering system
ORC-3 / OBR-3 Filler order number Assigned by the lab or RIS
OBR-4 Universal service identifier What was ordered; LOINC or a local code
OBR-7 Observation date/time Specimen collection time for lab
OBR-16 Ordering provider XCN
OBR-22 Results report/status change time Set on results
OBR-25 Result status (table 0123) F final, P preliminary, C corrected

Results: ORU^R01 and OBX value types

ORU^R01 sends results back, with one OBX per observation under the OBR they belong to.

MSH|^~\&|LIS|GENLAB|EHR|GENHOSP|20261006163000+0200||ORU^R01^ORU_R01|MSG00020|P|2.5.1
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||||||||||||||V000456^^^GENHOSP^VN
ORC|RE|ORD448811^CPOE|LAB99001^GENLAB|||||||||1001^MARTIN^CLAIRE^^^DR
OBR|1|ORD448811^CPOE|LAB99001^GENLAB|24321-2^Basic metabolic 2000 panel - Serum or Plasma^LN|||20261006151500+0200|||||||||1001^MARTIN^CLAIRE^^^DR||||||20261006162900+0200|||F
OBX|1|NM|2345-7^Glucose [Mass/volume] in Serum or Plasma^LN||182|mg/dL^^UCUM|70-99|H|||F|||20261006151500+0200
OBX|2|NM|2951-2^Sodium [Moles/volume] in Serum or Plasma^LN||139|mmol/L^^UCUM|136-145|N|||F|||20261006151500+0200
OBX|3|NM|2823-3^Potassium [Moles/volume] in Serum or Plasma^LN||4.1|mmol/L^^UCUM|3.5-5.1|N|||F|||20261006151500+0200
NTE|1||Fasting status not documented by the collector.
Field Name Notes
OBX-2 Value type (table 0125) Decides how to parse OBX-5
OBX-3 Observation identifier LOINC code^text^LN in the sample
OBX-4 Observation sub-ID Groups related OBX lines (microbiology, panels)
OBX-5 Observation value Can repeat
OBX-6 Units UCUM where the sender supports it
OBX-7 Reference range Free text such as 70-99
OBX-8 Abnormal flags (table 0078) H, L, N, A; renamed Interpretation Codes in later versions
OBX-11 Result status (table 0085) F final, P preliminary, C correction, X cannot be obtained
OBX-14 Date/time of the observation Clinically relevant time

Common OBX-2 value types:

Type Content Example OBX-5
NM Number 182
ST Short string POSITIVE
TX / FT Text / formatted text Report lines; FT allows formatting escapes
CE (CWE from v2.6) Coded answer POS^Positive^L
SN Structured numeric Comparator plus number, for ">200" style results
ED Encapsulated data Base64 PDF or image
DT / TS (DTM in later versions) Date or timestamp 20261006

Codes in OBX-3 are where terminology mapping starts; the LOINC and SNOMED CT mapping article picks up from here.

Scheduling: SIU^S12

SIU messages come from the scheduling system (the filler) when appointments are booked or changed. S12 is a new booking; S13 reschedule, S14 modification, S15 cancellation, S17 deletion and S26 no-show share the same SIU_S12 structure.

MSH|^~\&|SCHED|GENHOSP|EHR|GENHOSP|20261006170000+0200||SIU^S12^SIU_S12|MSG00030|P|2.5.1
SCH|APT5501^EHR|SCH7701^SCHED||||NEW^New appointment^LOCAL|FOLLOWUP^Follow-up^LOCAL|NORMAL^Normal^HL70277||||||||1001^MARTIN^CLAIRE^^^DR||||2001^CLERK^SAM|||||Booked^Booked^HL70278
TQ1|1||||||20261020093000+0200|20261020100000+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
RGS|1|A
AIS|1|A|FU30^Follow-up visit 30 min^LOCAL|20261020093000+0200|||30|min^minutes^UCUM
AIL|1|A|CARDCLIN^ROOM2^^GENHOSP
AIP|1|A|1001^MARTIN^CLAIRE^^^DR|ATT^Attending^LOCAL

SCH-1 and SCH-2 are the placer and filler appointment IDs, SCH-6 is the event reason, SCH-25 the filler status (Booked, Cancelled, Noshow...). TQ1-7 and TQ1-8 give start and end. The RGS group then lists resources: AIS for the service, AIL for the location, AIP for the person, AIG for anything else.

Documents: MDM^T02

MDM^T02 is "original document notification and content": a TXA header plus the document body in OBX. T01 is the same notification without content; T04, T06, T08 and T10 carry content for status changes, addenda, edits and replacements.

MSH|^~\&|TRANSCR|GENHOSP|EHR|GENHOSP|20261009171000+0200||MDM^T02^MDM_T02|MSG00040|P|2.5.1
EVN|T02|20261009171000+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||||||||||||||V000456^^^GENHOSP^VN
TXA|1|DS|TX|20261009170500+0200|1001^MARTIN^CLAIRE^^^DR|||||||DOC-2026-000881^TRANSCR|||||AU
OBX|1|TX|18842-5^Discharge Summary^LN||Admitted for hyperglycaemia.~Discharged home on oral therapy.||||||F

TXA-2 is the document type (DS discharge summary), TXA-12 the unique document number, TXA-17 the completion status (AU authenticated). Text bodies use TX or FT with one repetition per line; a PDF goes in an ED value, base64 encoded.

Charges: DFT^P03

DFT^P03 posts charges from an ancillary system (lab, pharmacy, radiology) to billing. One FT1 per charge line.

MSH|^~\&|LIS|GENLAB|BILLING|GENHOSP|20261006163500+0200||DFT^P03^DFT_P03|MSG00050|P|2.5.1
EVN|P03|20261006163500+0200
PID|1||MRN000123^^^GENHOSP&2.16.840.1.113883.19.5&ISO^MR||DOE^JANE^M^^^^L||19840312|F
PV1|1|I|4WEST^412^B^GENHOSP||||||||||||||||V000456^^^GENHOSP^VN
FT1|1|TX-0098812||20261006151500+0200||CG|300123^BASIC METABOLIC PANEL^LOCALCDM|||1|||||||||E11.9^Type 2 diabetes mellitus without complications^I10||1001^MARTIN^CLAIRE^^^DR||||80048^Basic metabolic panel^C4

FT1-4 is the transaction date, FT1-6 the type (CG charge, CD credit, PY payment, AJ adjustment), FT1-7 the chargemaster code, FT1-10 the quantity, FT1-19 the diagnosis, FT1-25 the procedure code (CPT-4 is coding system C4). Billing teams care far more about PV1-19 and PID-18 matching the right account than about anything clinical.

Acknowledgments: ACK and MSA

Every message above expects an ACK. MSA-1 carries the code from table 0008 and MSA-2 echoes the MSH-10 of the message being acknowledged.

MSH|^~\&|ENGINE|GENHOSP|ADTSYS|GENHOSP|20261006142801+0200||ACK^A01^ACK|ACK00001|P|2.5.1
MSA|AA|MSG00001

An error, pointing at PID-3 with error code 101 (required field missing) from table 0357:

MSH|^~\&|ENGINE|GENHOSP|ADTSYS|GENHOSP|20261006142801+0200||ACK^A01^ACK|ACK00002|P|2.5.1
MSA|AE|MSG00001
ERR||PID^1^3^1^1|101^Required field missing^HL70357|E
Mode When Codes Meaning
Original MSH-15 and MSH-16 both empty AA / AE / AR Application accepted / error / rejected
Enhanced, accept ack MSH-15 set (table 0155: AL, NE, ER, SU) CA / CE / CR Receiver committed the message to safe storage, or not
Enhanced, application ack MSH-16 set AA / AE / AR Sent later as a separate message once processed

If the sender had set MSH-15 to AL (and MSH-16 to NE), the same message would get a commit accept and nothing else:

MSH|^~\&|ENGINE|GENHOSP|ADTSYS|GENHOSP|20261006142801+0200||ACK^A01^ACK|ACK00003|P|2.5.1
MSA|CA|MSG00001

In practice, AE usually means "fix the data and resend", AR means "this message will never be accepted here" (wrong type, version or processing ID). A sender that retries AR forever fills its queue; decide which code triggers a retry and which goes to a human.

Pitfalls that break real interfaces

Z-segments. Segment IDs starting with Z are reserved for local definitions; HL7 will never define one. A ZPD after PID is legal, but its meaning lives only in the sender's interface specification. Ask for that document before you estimate, and make your parser keep unknown segments instead of failing on them.

Version differences. MSH-12 changes what a field means. PID-2, PID-4 and PID-19 are backward-compatibility fields in v2.5.1 and withdrawn in v2.7. TS becomes DTM, CE becomes CWE, OBX-8 becomes Interpretation Codes. v2.7 also adds a fifth encoding character, the truncation character, making MSH-2 ^~\&#. A parser that hard-codes four encoding characters will treat that # as data, so test it against a 2.7 or later header.

Escape sequences. A literal delimiter inside data must be escaped: \F\ field separator, \S\ component, \T\ subcomponent, \R\ repetition, \E\ escape character. Chapter 2 also defines \H\ and \N\ for highlighting and \X..\ for hex data, and FT fields allow formatting commands such as \.br\ for a line break. A comment containing "A&E" or "K+ ^ high" will split into components if the sender forgets to escape it.

Time zones in TS fields. The format is YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ] (v2.5.1 data types, DTM). Without the offset, the time is local to the sender. Fine on one campus, wrong as soon as a cloud receiver in UTC stores it, or when a feed crosses a daylight-saving change. Ask senders to include the offset, and store what you received.

Repeating PID-3 with assigning authority. PID-3 repeats with ~ and each repetition is a CX: ID, check digit, check digit scheme, assigning authority (CX-4, an HD such as namespace, OID and ISO), identifier type code (CX-5, MR, PI, AN...). Never take "the first PID-3" as the MRN. Match on assigning authority plus type, and quarantine messages where CX-4 is empty. Identity rules beyond that belong in a master patient index.

Empty versus null. An empty field means "no information sent"; two double quotes ("") mean "delete the stored value". Receivers that treat both the same either wipe data on every A08 or never clear anything.

Testing these samples

Every sample above can be pasted into the free HL7 v2 parser. It runs in the browser, so the message never leaves your machine; it labels every field and component by position (PID.3.1, OBX.5...) and can export the result as JSON. For a channel that receives these over MLLP, filters by MSH-9 and transforms to FHIR, see the Mirth Connect channel architecture guide; if you are still choosing a tool, start with the interface engine comparison.

If you need someone to write an interface specification, build the channels or review a v2 feed before go-live, that is the work of the HL7 and FHIR integration service.

HL7 v2ADTORUORMSIUMDMDFTACKPIDOBXInteroperability

Related reading and services

Let's Continue the Conversation

Have questions about this topic? I'd love to hear from you.