HL7 stands for Health Level Seven, and the name means two things:
- HL7 International, the standards organization. The "seven" refers to the application layer, layer 7 of the OSI networking model.
- HL7 version 2 (HL7 v2), the messaging standard most people mean when they say "HL7". It dates from the late 1980s and is still how most hospital systems exchange information.
The same organization also publishes FHIR, a newer standard built on web APIs and JSON. FHIR is growing fast for apps and data sharing between organizations, but inside hospitals the day-to-day traffic is still mostly v2. This article is about v2.
What HL7 v2 is used for
Whenever something happens to a patient, one system tells the others with an HL7 v2 message:
- a patient is admitted, transferred or discharged (ADT messages), so the lab, pharmacy, billing and bed-management systems all know;
- a doctor orders a test (ORM or OML), and the result comes back (ORU);
- an appointment is booked or cancelled (SIU);
- a report or document is created (MDM);
- charges are posted (DFT), or a vaccination is reported to a registry (VXU).
What a message looks like
An HL7 v2 message is plain text. Here's the start of an admission message:
MSH|^~\&|REGADT|MERCY GENERAL|ANALYTICS|DATAHUB|20260114083000||ADT^A01^ADT_A01|MSG00001|P|2.5.1
EVN|A01|20260114083000
PID|1||MRN100234^^^MERCY^MR||SAMPLE^JANE^Q||19800101|F||2106-3^White^CDCREC|100 TEST ST^^SPRINGFIELD^IL^62701^USA||^PRN^PH^^^555^5550100|||M||ACCT5001^^^MERCY^AN
PV1|1|I|4WEST^401^A^MERCY|E|||1234^ATTEND^AMY^^^DR|||MED||||7|||1234^ATTEND^AMY^^^DR|IP|VIS7001^^^MERCY^VN
It's dense, but it follows a few simple rules.
The building blocks
| Level | Separated by | Example |
|---|---|---|
| Segment | A new line (a carriage return) | Each line above is one segment. The first three letters name it: MSH message header, PID patient identification, PV1 patient visit |
| Field | | | SAMPLE^JANE^Q is field 5 of PID, written PID-5 |
| Component | ^ | In PID-5, SAMPLE is the family name (PID-5.1), JANE the given name (PID-5.2), Q the middle initial (PID-5.3) |
| Repetition | ~ | A field that holds a list, such as two patient identifiers: MRN100234^^^MERCY^MR~E5550123^^^MERCYEMPI^PI |
| Subcomponent | & | A component split further, used in a few complex data types |
The separator characters are declared in the first two fields of MSH: | in MSH-1 and ^~\& in MSH-2. The \ is the escape character, used when a value needs to contain one of the separators (see escape sequences).
The MSH counting quirk. In every other segment, the first | comes after the segment name and field 1 follows it. In MSH, the first | is field 1. So if you count pipes by hand in an MSH segment, you'll be off by one: REGADT is MSH-3, not MSH-2.
Reading the example, field by field
MSH: the envelope
| Field | Value | Means |
|---|---|---|
MSH-3 / MSH-4 | REGADT / MERCY GENERAL | Sending application and facility |
MSH-5 / MSH-6 | ANALYTICS / DATAHUB | Receiving application and facility |
MSH-7 | 20260114083000 | When the message was created: 14 January 2026, 08:30:00 |
MSH-9 | ADT^A01^ADT_A01 | Message type ADT, trigger event A01 (admit), message structure ADT_A01 |
MSH-10 | MSG00001 | Message control ID: a unique ID the receiver echoes back in its acknowledgment |
MSH-11 | P | Processing ID: P production, T training, D debugging |
MSH-12 | 2.5.1 | The HL7 v2 version the message follows (not always accurately) |
PID: who the patient is
| Field | Value | Means |
|---|---|---|
PID-3 | MRN100234^^^MERCY^MR | Patient identifier: ID MRN100234, assigned by MERCY, of type MR (medical record number, from table 0203) |
PID-5 | SAMPLE^JANE^Q | Name: family, given, middle |
PID-7 | 19800101 | Date of birth, written YYYYMMDD |
PID-8 | F | Administrative sex: F = Female (table 0001) |
PID-11 | 100 TEST ST^^SPRINGFIELD^IL^62701^USA | Address: street, (other designation), city, state, ZIP, country |
PV1: the visit
| Field | Value | Means |
|---|---|---|
PV1-2 | I | Patient class: I = Inpatient (table 0004) |
PV1-3 | 4WEST^401^A^MERCY | Location: unit 4WEST, room 401, bed A, facility MERCY |
PV1-7 | 1234^ATTEND^AMY^^^DR | Attending doctor: ID 1234, Dr Amy Attend |
PV1-19 | VIS7001^^^MERCY^VN | Visit number, which identifies this encounter |
Notice how much depends on position. Nothing in the text says "date of birth"; it's simply the 7th field of PID. That's why HL7 v2 is hard to read without a reference, and why code values such as I or MR only make sense with the right code table.
Message types and trigger events
MSH-9 combines a message type (what kind of message) with a trigger event (what happened). The same type covers many events:
| Message | What happened |
|---|---|
ADT^A01 | Patient admitted |
ADT^A04 | Patient registered (outpatient or emergency) |
ADT^A08 | Patient information updated |
ADT^A03 | Patient discharged |
ORU^R01 | Results sent, such as lab results |
SIU^S12 | Appointment booked |
There are hundreds of trigger events. The trigger events reference lists them all.
How messages travel
- Transport. Most v2 messages travel over a plain TCP connection using MLLP (the Minimal Lower Layer Protocol), which wraps each message in a start byte (hex
0B) and an end sequence (hex1C 0D). Files and other transports are used too. - Acknowledgments. The receiver replies to each message with an ACK. Its MSA segment says whether the message was accepted (
AA), had an error (AE) or was rejected (AR), and it repeats the original control ID fromMSH-10:MSH|^~\&|ANALYTICS|DATAHUB|REGADT|MERCY GENERAL|20260114083001||ACK^A01^ACK|ACK00001|P|2.5.1 MSA|AA|MSG00001 - Interface engines. Hospitals usually route messages through an interface engine that receives each message once, transforms it for each destination and sends it on.
Versions, code tables and local customization
- Versions. HL7 v2 has many versions, from 2.1 up to 2.9 and later. Newer versions add segments, fields and components, and mostly keep the old ones, so a v2.3 receiver can often read a v2.5 message. "Often" is the catch.
- Code tables. Coded fields take their values from numbered tables. Some are HL7-defined, with fixed values; many are user-defined, where HL7 only suggests values and each site uses its own.
- Z-segments. Anything the standard doesn't cover goes into custom segments whose names start with Z, such as
ZPI. Their meaning is whatever the two sides agree. - Interface specifications. Because of all this flexibility, every interface needs a specification saying exactly which segments, fields and codes the sender uses. Two "HL7 v2.5 ADT feeds" from different vendors can look quite different.
Where to go next
- Look up any code table or trigger event in the HL7 v2 reference.
- Learn the escape sequences that show up in text fields.
- Paste a real message into PipeHat to see every field named and explained, checked against every version from 2.1 to 2.8.2. It runs in your browser, so the message never leaves your computer.