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

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.