HL7 ADT to FHIR: mapping Patient and Encounter from A01, A04, A08 and A03
A playbook for projecting HL7 v2 ADT A01, A04, A08 and A03 onto FHIR Patient and Encounter — PID-3 versus identifier.system, PV1-19 visit numbers, and de-identified test fixtures.
Ala Ben Aicha

Direct answer
ADT A01, A04 and A08 project PID to Patient and PV1 to Encounter. A03 ends the visit. PID-3 is Patient.identifier; PV1-19 is the visit number. Pin assigning authorities before you upsert.
Message and resource mapping
Pin the published HL7 Version 2 to FHIR IG 1.0.0 (STU 1) (generated 7 October 2025, package hl7.fhir.uv.v2mappings#1.0.0 on FHIR R4). The STU 1 message maps include ADT_A01 → Bundle. A04, A08 and A03 are still Chapter 3 Patient Administration trigger events; they reuse the same PID → Patient and PV1 → Encounter segment maps even when a dedicated message ConceptMap is not in that STU.
| Trigger (MSH-9) | v2 event | FHIR effect | Status / class notes |
|---|---|---|---|
| ADT^A01 | Admit / visit notification | Upsert Patient from PID; upsert Encounter from PV1; Encounter.subject → that Patient |
Encounter.class from PV1-2 (table 0004 → ActCode: I→IMP, O→AMB, E→EMER). Status in-progress when PV1-45 is empty |
| ADT^A04 | Register a patient | Same Patient + Encounter pair | Typically outpatient (PV1-2 = O → AMB). Not a bed assignment |
| ADT^A08 | Update patient information | Patch Patient; update Encounter only when PV1 is present and the visit is already known | Not a new visit. Do not mint a second Encounter.identifier |
| ADT^A03 | Discharge / end visit | Encounter.status → finished; Encounter.period.end from PV1-45 |
Do not delete Patient. Do not reuse the visit number on the next A01 |
Segment-level pins from the IG:
| v2 field | FHIR path | Type map |
|---|---|---|
| PID-3 Patient Identifier List | Patient.identifier |
CX → Identifier |
| PID-5 Patient Name | Patient.name |
XPN → HumanName |
| PID-7 Date/Time of Birth | Patient.birthDate |
TS → date |
| PV1-2 Patient Class | Encounter.class |
CWE → Coding (ActCode) |
| PV1-19 Visit Number | Encounter.identifier |
CX → Identifier, type VN (http://terminology.hl7.org/CodeSystem/v2-0203) |
| PV1-44 Admit Date/Time | Encounter.period.start |
|
| PV1-45 Discharge Date/Time | Encounter.period.end |
MSH still becomes MessageHeader / Provenance. EVN-2 is event time, not a second birth date. NK1 is RelatedPerson or Patient.contact, not another Patient. This page does not map A40 merges — that is an MPI problem, covered in the master patient index article.
The hybrid engine pattern (keep v2 as the hospital nervous system, project FHIR for new consumers) is the v2-to-FHIR migration playbook. This page is the ADT mapping contract inside that engine.
Identifier traps
PID-3 is a repeating CX. Each repeat is ID^^^AssigningAuthority^IdentifierType. FHIR needs identifier.system (the assigning authority as a URI you actually own) and identifier.value. A bare MRN string with no system will collide the first time two hospitals share a FHIR server.
Do not put PV1-19 on Patient.identifier. The IG types the visit number as VN. PID-18 (Patient Account Number) is not the visit number; the PID map even warns that some senders stuff a visit id into PID-18 — if yours does, treat it as a documented exception, not as the default.
National identifiers (AHV, NHS number, KVNR, IHI) belong in PID-3 with their published system URIs. Local MRNs stay local. The MPI article is where matching rules live; the ADT mapper's job is to preserve the CX, not to invent a golden record.
| Trap | Symptom | Fix |
|---|---|---|
| PID-3 without assigning authority | Duplicate Patient resources on the first A08 | Require CX.4 (or CX.4.2 namespace ID) before upsert; reject or quarantine |
| PV1-19 copied onto Patient | Two patients share a visit number after transfer | Visit → Encounter.identifier only |
| A08 creating Encounter | Census doubles on demographic fixes | Match Encounter by PV1-19 + Patient; insert only on A01/A04 |
| A03 deleting Patient | Downstream Observation orphans | Patient stays; Encounter.status = finished |
| MSH-3 / MSH-4 as identifier.system | Systems collide when a vendor reuses a facility name | Pin a URI per sending application × assigning authority |
Test fixtures
De-identified examples only. These values are specification fixtures, not a person.
MSH|^~\&|HIS|HOSP-A|FHIR-BRIDGE|HOSP-A|20260917103000||ADT^A01^ADT_A01|MSG0001|P|2.5
EVN|A01|20260917103000
PID|1||HOSP-MRN-0001^^^HOSP-A^MR||EXAMPLE^JANE^Q||19770412|F|||1 TEST STREET^^TESTVILLE^TN^10000
PV1|1|I|WARD-A^101^A||||ATTEND^SMITH^A|||SUR||||A0|||||VN-2026-00042^^^HOSP-A^VN|||||||||||||||||||||||||20260917103000
Projected Patient (truncated):
{
"resourceType": "Patient",
"identifier": [
{
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR"
}
]
},
"system": "https://hosp-a.example.org/mrn",
"value": "HOSP-MRN-0001"
}
],
"name": [{ "family": "EXAMPLE", "given": ["JANE", "Q"] }],
"birthDate": "1977-04-12",
"gender": "female"
}
Projected Encounter (truncated):
{
"resourceType": "Encounter",
"status": "in-progress",
"class": {
"system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code": "IMP"
},
"identifier": [
{
"type": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "VN"
}
]
},
"system": "https://hosp-a.example.org/visit",
"value": "VN-2026-00042"
}
],
"subject": { "reference": "Patient?identifier=https://hosp-a.example.org/mrn|HOSP-MRN-0001" },
"period": { "start": "2026-09-17T10:30:00+01:00" }
}
Minimum fixture set before cutover:
- A01 then A08 (name correction) — one Patient, one Encounter, name updated.
- A01 then A03 — Encounter.period.end set, status finished, Patient still searchable.
- A04 outpatient register — class AMB, no bed in
Encounter.locationunless PV1-3 is valued. - Two A01 with the same PID-3 and different PV1-19 — two Encounters, one Patient.
- A08 with missing PV1-19 — Patient updates; no new Encounter.
Never copy a live PID into a ticket, a git repo, or this site.
Failure modes and rollback
| Failure | Detection | Rollback |
|---|---|---|
| Duplicate Patient | Two resources share PID-3 value with different systems, or the same system after a mapper bug | Stop the writer; merge only with an agreed MPI rule; replay A08 from the v2 store |
| Duplicate Encounter | Two in-progress Encounters for one PV1-19 | Treat PV1-19 + assigning authority as the natural key; close the extra as entered-in-error |
| Late A03 | Census still shows in-progress after discharge | Idempotent A03: set status and period.end; do not require the original A01 in the same process |
| A08 applied as A01 | Extra visits on demographic noise | Filter MSH-9.2 before insert; A08 is PATCH |
| Loop with a FHIR subscription that re-emits ADT | Message volume cliff | One authoritative write path; provenance on the projected resources; suppress echo by MSH-3 |
Keep v2 as the source of truth until the FHIR Patient/Encounter pair has a named owner, an ACK policy, and a replay from the engine's message store. The migration playbook covers shadow, dual-write and cutover as architecture. This mapper must still be able to disable the FHIR writer without touching the HIS ADT feed.
Related service
If you need the mapping implemented on an engine (NextGen Connect / Mirth, or a FHIR facade in front of a v2 feed), that is HL7 FHIR integration. For a scoped ADT→Patient/Encounter spike, use contact with project intent.
This page is not a conformance certificate against the v2-to-FHIR IG, not an MPI product, and not clinical advice about admission or discharge.