# HL7v2 to FHIR - references and deduplication

Deliver each HL7v2 message as one consistent resource graph - fullUrl and urn:uuid references, deduplication and bundle\_type effects.

A single HL7v2 message usually describes several connected entities - a patient, their visit, the attending doctor, lab results. The [conversion](https://zato.io/docs/dev/healthcare/hl7/to-fhir/index.html) turns each of them into a separate resource and wires the connections between them, so the bundle arrives at the FHIR server as one consistent graph.

## Every entry has a fullUrl {#every-entry-has-a-fullurl}

Each bundle entry includes a `fullUrl` in the `urn:uuid:` form and other entries reference it through that URL:

```json
{
  "fullUrl": "urn:uuid:237f706c-3f37-5ee3-98bf-fe8c006c2aa5",
  "resource": {
    "resourceType": "Encounter",
    "subject": {
      "reference": "urn:uuid:98e4f8aa-a5ad-5791-add1-66fd3afb4f83"
    }
  }
}
```

Here the Encounter's `subject` points at the Patient entry from the same bundle. When a FHIR server processes the transaction, it assigns real IDs to the created resources and rewrites all the `urn:uuid:` references to point at them - the graph stays intact on the server side.

The UUIDs are deterministic - they derive from the resource's content, so converting the same message twice yields the same URLs, which makes bundles reproducible and easy to compare in tests.

The references set by the conversion include:

- `Encounter.subject`, `Observation.subject`, `Condition.subject` and every other clinical resource pointing at the Patient
- `MessageHeader.focus` pointing at the Patient and the Encounter, with `sender` and the destination's `receiver` pointing at the facility Organizations from MSH-4 and MSH-6
- `Encounter.participant` and `Encounter.location` pointing at Practitioners and Locations, and each Location's `partOf` pointing at the one that contains it
- `DiagnosticReport.basedOn` pointing at the ServiceRequest, `DiagnosticReport.result` at Observations, `DiagnosticReport.specimen` at Specimens
- `Coverage.payor` pointing at the insurer Organization

The bundle itself records the message's identity too - `identifier` is the MSH-10 control ID, `timestamp` the MSH-7 message time and `meta.tag` the MSH-11 processing ID.

## Deduplication {#deduplication}

The same entity often appears multiple times in one message - the same doctor in PV1-7 and ORC-12, the same organization in several IN1 segments. Practitioner, Location, Organization and Device resources with identical content are created once, and every later occurrence becomes a reference to the first one:

```python
from zato.hl7v2 import parse_hl7

raw = (
    'MSH|^~\\&|SENDER|FACILITY|RECEIVER|FAC|20260315101112||ADT^A01^ADT_A01|CTL001|P|2.9\r'
    'PID|||12345^^^HOSP^MR||SMITH^JOHN^A||19800115|M\r'

    # The same doctor is both the attending and the referring physician ..
    'PV1|1|I|WARD^101^BED1||||1234^JONES^MARIA|1234^JONES^MARIA\r'
)

msg = parse_hl7(raw, validate=False)
bundle = msg.to_fhir()

# .. yet the bundle contains a single Practitioner.
for entry in bundle.entry:
    print(entry.resource.resource_type)
```

```text
MessageHeader
Organization
Organization
Patient
Location
Location
Location
Practitioner
Encounter
```

Both `Encounter.participant` entries point at the one Practitioner. The three Locations are the ward, the room and the bed from PV1-3, each `partOf` the one before it. Deduplication is content-based and limited to the four resource types that are never changed after they are created - Practitioner, Location, Organization and Device. A Patient or an Encounter is built up by several segments, so two of them are never merged.

## What bundle\_type changes {#what-bundle_type-changes}

By default the bundle is a **transaction** - the server applies all entries atomically and each entry has a `request` with `POST` and the resource type as the URL. The [configuration file](https://zato.io/docs/dev/healthcare/hl7/to-fhir/config/index.html) can change this:

```ini
[bundle]
type=batch
```

- `transaction` - all or nothing, the server rolls everything back if any entry fails
- `batch` - the same entries, but each is processed independently and failures do not affect the other entries
- `collection` - no `request` elements at all, the bundle is a plain container of resources, useful for storing or forwarding the conversion result without a FHIR server interaction
- `message` - no `request` elements either, the bundle is a FHIR message whose first entry is the MessageHeader, for servers that accept messages at `$process-message`

In all four cases the `fullUrl` values and the `urn:uuid:` references stay the same.

## See also {#see-also}

- [What you get per message](https://zato.io/docs/dev/healthcare/hl7/to-fhir/resources/index.html) - The resources the references connect, per message family
- [Sending bundles to FHIR servers](https://zato.io/docs/dev/healthcare/hl7/to-fhir/sending/index.html) - How servers rewrite the urn:uuid references into real IDs
- [Configuration](https://zato.io/docs/dev/healthcare/hl7/to-fhir/config/index.html) - The bundle type setting and everything else the .ini file holds

## Learn more {#learn-more}

- [Healthcare interface engine](https://zato.io/docs/dev/healthcare/) - Clinical messages, FHIR, conversion and operations
- [HL7 v2 parsing](https://zato.io/docs/dev/healthcare/hl7/v2/parsing/) - Messages as typed objects, with field access and validation
- [MLLP channels](https://zato.io/docs/dev/healthcare/hl7v2/mllp/) - Receiving and sending HL7 v2 over MLLP sockets
- [FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/) - Read and write FHIR resources, with paths, bundles and extensions
- [HL7 v2 to FHIR](https://zato.io/docs/dev/healthcare/hl7/to-fhir/) - Converting v2 messages into FHIR bundles, codes and references included
- [EDIFACT](https://zato.io/docs/dev/healthcare/edifact/) - Parsing interchanges, dialects and the transports they arrive on
- [Transformation](https://zato.io/docs/dev/healthcare/transformation/) - One message in, another standard out, in ordinary Python
- [Audit log](https://zato.io/docs/dev/healthcare/audit-log.html) - Every message with its acknowledgment, searchable by patient identifier
- [AI in clinical interfaces](https://zato.io/docs/dev/healthcare/ai/) - Services calling LLMs and AI agents calling clinical services as tools
