PipeHat Open PipeHat
LEARN | OCTOBER 17, 2026

What is HL7? A practical introduction to HL7 v2 messages

A plain-English tour of HL7 version 2: who uses it, how a message is put together, how to read one field by field, and how messages travel between systems.

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

LevelSeparated byExample
SegmentA 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

FieldValueMeans
MSH-3 / MSH-4REGADT / MERCY GENERALSending application and facility
MSH-5 / MSH-6ANALYTICS / DATAHUBReceiving application and facility
MSH-720260114083000When the message was created: 14 January 2026, 08:30:00
MSH-9ADT^A01^ADT_A01Message type ADT, trigger event A01 (admit), message structure ADT_A01
MSH-10MSG00001Message control ID: a unique ID the receiver echoes back in its acknowledgment
MSH-11PProcessing ID: P production, T training, D debugging
MSH-122.5.1The HL7 v2 version the message follows (not always accurately)

PID: who the patient is

FieldValueMeans
PID-3MRN100234^^^MERCY^MRPatient identifier: ID MRN100234, assigned by MERCY, of type MR (medical record number, from table 0203)
PID-5SAMPLE^JANE^QName: family, given, middle
PID-719800101Date of birth, written YYYYMMDD
PID-8FAdministrative sex: F = Female (table 0001)
PID-11100 TEST ST^^SPRINGFIELD^IL^62701^USAAddress: street, (other designation), city, state, ZIP, country

PV1: the visit

FieldValueMeans
PV1-2IPatient class: I = Inpatient (table 0004)
PV1-34WEST^401^A^MERCYLocation: unit 4WEST, room 401, bed A, facility MERCY
PV1-71234^ATTEND^AMY^^^DRAttending doctor: ID 1234, Dr Amy Attend
PV1-19VIS7001^^^MERCY^VNVisit 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:

MessageWhat happened
ADT^A01Patient admitted
ADT^A04Patient registered (outpatient or emergency)
ADT^A08Patient information updated
ADT^A03Patient discharged
ORU^R01Results sent, such as lab results
SIU^S12Appointment 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 (hex 1C 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 from MSH-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.

Related