HL7 Messages Guide
HL7 messages are often introduced as lists of segments, but that is only half the story. A message is a workflow event wrapped in a structure. The sender is saying that something happened, or that it needs something to happen, and the receiver decides whether it can accept, route, store, transform, acknowledge, or reject that event.
The searchable list on the left is the catalogue of message structures. This guide is the practical map: how to read message type, trigger event, and message structure together; how common message families behave; and where interfaces usually go wrong when they treat messages as just another file format.
Start with MSH-9, but do not stop there
MSH-9 Message Type is the first serious clue to what a message is. In modern v2 feeds it is usually carried as the MSG data type with three components: message code, trigger event, and message structure. For example, ADT^A01^ADT_A01 says the message family is ADT, the trigger event is A01, and the parser should expect the ADT_A01 structure.
Those three pieces answer different questions:
The HL7 v2+ MSG data type describes those three components as message code, trigger event, and message structure. The HL7 v2 control chapter also notes that receivers validate whether MSH-9 is acceptable, and that abstract message syntax defines segment order, optionality, repetition, and choices. See HL7 v2+ MSG and HL7 v2.4 Chapter 2 for the standards-side detail.
Trigger events are workflow, not decoration
The trigger event is the part people are most tempted to ignore. That is risky. ADT_A01, ADT_A03, and ADT_A08 are all ADT messages, but they do not mean the same thing. One opens or notifies an admission, one ends a visit, and one updates patient or visit information. A receiver may route them to different queues, apply different state transitions, or reject one if the patient state does not make sense.
The same shape can also be used for different events. Several ADT events share similar structures, but the event still changes the operational meaning. The right implementation question is not just "can I parse the segments?" It is "what should this event do to the receiving system?"
Local Z events and custom message types are sometimes necessary, but they are also a contract. If a sender invents ADT^Z99, every receiver, monitor, transformer, and support process has to know what Z99 means. If only one interface engine map understands it, the message is not portable.
Common message families
Message structure is a parser contract
The message structure is not just a name. It tells the receiver which segments and groups can appear, which are required, which repeat, and where optional groups belong. In ORU_R01, for example, patient, order, observation, and sometimes specimen information sit inside repeating groups. In ADT_A01, the patient and visit backbone is much flatter, with optional allergy, diagnosis, procedure, guarantor, and insurance context.
That means a receiver should not parse by "find the next OBX anywhere" when the message structure tells you which order, specimen, or patient result group the OBX belongs to. Segment position and grouping are part of the meaning.
Optional does not mean irrelevant. Optional segments are often required by a local profile. A base message might allow many shapes, while your trading partner agreement says "PID, PV1, ORC, OBR, and at least one OBX are mandatory for this feed." The guide page for each message structure is the starting point; the interface specification is what narrows it for production.
ACKs are part of the message design
Every production interface needs a clear acknowledgment story. ACK, MSA, and ERR are not afterthoughts. They are how senders know whether a receiver accepted, errored, or rejected a message and whether retrying, correcting, or escalating makes sense.
The old/simple ACK pattern is enough for some feeds: receive a message, validate it, process it, and return AA, AE, or AR. Enhanced acknowledgment separates accept acknowledgment from application acknowledgment, which matters when a receiver can safely store a message before later application processing completes.
Whatever mode you choose, make it explicit. If an invalid message type, unsupported trigger event, wrong version, unknown processing ID, duplicate control ID, or bad required segment is rejected, the sender should get a useful response rather than a silent timeout or a generic failure.
Choosing the right message
When you are deciding which message to use, start with the business event, not the nearest segment list.
Real interfaces often mix concerns. A result message may include patient and visit information. A document message may carry OBX content. A billing message may include diagnoses and procedures. That does not mean any message can do anything. It means the message family tells you the main event, while the segments supply the supporting story.
Version and profile matter
The same visible message name can change across HL7 versions. New segments appear, optional groups move, data types get richer, and older fields stay for backward compatibility. A receiver that accepts ORU^R01 in v2.3.1 may not accept the same assumptions in v2.5.1, especially around specimens, coded values, and acknowledgment handling.
MSH-12 Version ID and MSH-21 Message Profile Identifier are not decorative. The version tells the parser which base contract applies. The profile tells the receiver which implementation guide or local constraints apply. If a national lab guide says OML^O21^OML_O21 with a specific set of required segments, that profile beats a casual "we send lab orders" description.
Best practices that save support time
A practical message review workflow
When reviewing a feed, I usually start with five questions:
In HL7 Soup Web, open representative messages and compare MSH-9, MSH-12, the visible segment order, and the message structure side by side. In Integration Soup, make message routing and transformations event-aware: ADT updates, ORU result handling, SIU schedule changes, MDM document filing, and ACK paths should be deliberate mappings rather than one broad "HL7 in, HL7 out" rule. The Integration Host getting-started tutorial and transformer tutorial are useful next steps when the guide turns into running interfaces.
Useful messages to learn first
What to do next
Pick one live interface and write down the message code, trigger event, structure, version, profile, required segments, repeating groups, ACK behavior, and supported event sequence. If that list is not clear, the interface may still work in the happy path, but support will struggle the moment a cancellation, correction, duplicate, merge, or local event appears.