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:

MSH-9 part Example What it tells you
Message code ADT, ORU, ORM, SIU, MDM The broad family of the message: patient administration, results, orders, scheduling, documents, and so on. See table 0076 Message Type.
Trigger event A01, A03, R01, O01, S12, T02 The real-world event that caused the message. See table 0003 Event Type.
Message structure ADT_A01, ORU_R01, SIU_S12, OML_O21 The segment layout the receiver should parse, including required segments, optional groups, repeating groups, and choices.

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

Family Common examples Typical job
ADT ADT_A01, ADT_A02, ADT_A03, ADT_A04, ADT_A08 Patient administration: admit, transfer, discharge, register, update, merge, cancel, and visit-state workflows.
ORM / OML ORM_O01, OML_O21 Orders and lab orders: placer/filler identifiers, order control, requested service, timing, specimen, and ordering provider context.
ORU / OUL ORU_R01, OUL_R22 Results and observations: patient, visit, order, specimen, observation values, narrative reports, microbiology, and device or lab output.
SIU SIU_S12, SIU_S13, SIU_S14 Scheduling: appointments, resources, locations, services, personnel, changes, cancellations, and no-shows.
MDM MDM_T02, MDM_T08 Document management: new documents, replacements, edits, availability, status, and filing metadata.
DFT / BAR DFT_P03, BAR_P01 Financial and account workflows: charges, account updates, billing classifications, diagnoses, procedures, and coverage context.
VXU VXU_V04 Immunization updates: patient, vaccination administration, lot/manufacturer, route/site, observation details, and registry reporting.
ACK ACK Acknowledgment: tells the sender whether a message was accepted, errored, or rejected, and should point to useful error detail.

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.

  • If a patient is admitted, transferred, discharged, registered, updated, or merged, look at the ADT family.
  • If a placer is asking a filler to do work, look at order messages such as ORM or OML, depending on version and workflow.
  • If a filler is reporting observations, look at ORU or OUL, and pay attention to specimen and observation grouping.
  • If the event is an appointment lifecycle event, look at SIU and the SCH/AIS/AIG/AIL/AIP resource pattern.
  • If the event is a document lifecycle event, look at MDM and TXA/OBX document handling.
  • If the event is financial, claims-adjacent, or charge-related, look at DFT, BAR, FT1, IN1, GT1, DG1, and PR1.
  • If the event is public-health or registry reporting, start with the implementation guide, not just the base message name.

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

  • Validate MSH-9 as three related components. Message code, trigger event, and structure should agree with the version and profile.
  • Route by event intentionally. Do not send A01, A03, and A08 through identical business logic unless you truly want identical state changes.
  • Preserve message control IDs. MSH-10 and MSA-2 are how ACKs and retries stay traceable.
  • Understand repeating groups. Especially in ORU, OML, OUL, SIU, and query responses, repeated groups are meaning, not noise.
  • Do not promote optional base segments to optional production behavior by accident. Your profile may require them.
  • Keep local Z content documented. Z-segments, Z-events, and custom structures are fine when they are explicit, versioned, and tested.
  • Return useful ACKs. Include ERR detail when rejecting unsupported events, missing required fields, bad codes, or impossible state transitions.
  • Test event sequences, not just single messages. Admit, update, transfer, discharge, cancel, result correction, document replacement, and order cancellation behavior often breaks across sequences.

A practical message review workflow

When reviewing a feed, I usually start with five questions:

  1. What real-world event caused this message?
  2. Do MSH-9.1, MSH-9.2, and MSH-9.3 agree with that event and the structure on the wire?
  3. Which segments or groups does the receiver need to make a safe state change?
  4. What ACK should come back for unsupported events, missing required data, duplicates, and business-rule failures?
  5. What sequence of messages should be tested before go-live?

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.

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.