← all articles

HL7 ADT Messages Explained: Admission, Discharge and Transfer

If you build one HL7 interface in your career, it will almost certainly be an ADT interface. ADT stands for Admission, Discharge and Transfer, and despite that name it carries far more than those three events. Almost every movement a patient makes through a health service, and almost every change to their demographic record, is communicated as an ADT message.

ADT is the foundation other interfaces are built on. A pathology system cannot file a result against a patient it has never heard of. A scheduling system cannot book an appointment for someone who does not exist in its database. ADT is what puts the patient there in the first place, and what keeps that record accurate afterwards.

What ADT actually carries

The message type is ADT, and the specific event is carried in a trigger event code — A01, A08 and so on. The ones you will meet constantly:

  • A01 — admit/visit notification. A patient has been admitted. This creates or activates an inpatient episode in downstream systems.
  • A03 — discharge/end visit. The episode is over. Downstream systems close out their view of it.
  • A04 — register a patient. An outpatient or emergency registration, rather than an inpatient admission.
  • A08 — update patient information. By volume, usually the most common message on the interface. A name correction, a new address, a changed phone number, an updated GP.
  • A02 — transfer a patient. The patient has moved ward, bed or location within the facility.
  • A11, A13 — cancel admit, cancel discharge. Somebody did something by mistake, and downstream systems need to unwind it.
  • A28, A31 — add and update person information. Demographic records maintained independently of any particular visit.
  • A40 — merge patient identifiers. Two records turned out to be the same human being.

That last one deserves particular attention, and I will come back to it.

Why ADT feeds are the hardest easy interface

Reading a specification, ADT looks straightforward. A message arrives, you parse the PID segment, you upsert a patient. In production, several things reliably bite.

Order matters, and the network does not care. If an A08 update overtakes the A01 that created the patient, a naive receiver either errors or, worse, creates a duplicate record from the update. Anything that processes ADT in parallel needs to preserve per-patient ordering, or detect and handle out-of-order arrival explicitly.

A08 does not tell you what changed. It is a full snapshot of the patient, not a delta. If your system reacts to changes — sending a notification, triggering a workflow — you have to diff against what you already held. Systems that treat every A08 as "something changed" generate an enormous amount of noise, because most A08 messages change nothing you care about.

Cancellations are not deletions. An A11 cancel-admit means the admission should never have existed. That is different from a discharge, and different again from simply removing the record. Downstream systems that treat a cancellation as a discharge leave a phantom completed episode behind, and it will surface later in a report nobody can reconcile.

Merges rewrite history. An A40 says that patient identifier X and patient identifier Y are the same person, and one of them now wins. Every record you hold against the losing identifier needs to move. Systems that ignore merges accumulate split records that clinicians eventually notice, usually at the worst possible moment.

Building an ADT interface that stays reliable

A few practices that have saved me repeatedly:

Persist the raw message before you parse it. When a downstream team asks why a patient's address is wrong, being able to produce the exact message you received, byte for byte, ends the argument in minutes instead of days.

Acknowledge honestly. HL7 acknowledgements exist so the sender knows whether to retry. An interface that returns AA (application accept) regardless of what happened is lying, and it converts a recoverable failure into permanent data loss. If you could not process the message, say so.

Reconcile, don't assume. Message counts are not proof of correctness. A periodic reconciliation between your patient index and the source system will find the gaps that message-level monitoring never will.

Test against real message shapes. Every site sends slightly different ADT. Optional fields are populated or not, Z-segments appear, field lengths surprise you. Build a safe test environment with realistic messages rather than discovering site-specific quirks in production.

Where ADT fits with everything else

ADT rarely runs alone. It establishes and maintains the patient, and other message types then reference that patient: SIU books their appointments, ORM requests their tests, ORU returns the results, and DFT records what should be billed. Get ADT wrong and everything downstream inherits the problem.

FHIR expresses the same information as Patient and Encounter resources, and many organisations now transform ADT feeds into exactly that. The underlying events do not change — only the shape they travel in.

If you need an ADT interface built, migrated or rescued, that is most of what I do.

Matthew Ratcliffe, software developer and architect, Ballarat
Senior Software Engineer & Architect

20+ years across the technology stack — from greenfield builds to brownfield rescues. Based in Ballarat, VIC, focused on AI, healthcare and high-risk data systems. Full resume →

Share your thoughts