# HL7 v2 to FHIR mapping

> Segment-to-resource and OBX field-by-field mapping from HL7 v2 ORU^R01 to FHIR R4, the traps that break integrations, and a converter you call over HTTPS.

Source: https://developers.anpheros.com/guides/hl7-v2-to-fhir-mapping

**Mapping HL7 v2 to FHIR means turning each segment of a pipe-delimited v2 message into FHIR R4 resources: PID into a Patient, OBR into a DiagnosticReport (or ServiceRequest), each OBX into an Observation, with codes, units, ranges and times carried over field by field.** HL7 publishes an official [V2-to-FHIR implementation guide](https://hl7.org/fhir/uv/v2mappings/) with concept maps for the common segments. This page gives the practical mapping for laboratory results (ORU^R01), the traps that break real integrations, and a converter you can call over HTTPS: the Anpheros lab connector.

<!-- visual:v2map-flow -->

## Segment to resource

| HL7 v2 segment | What it carries | FHIR R4 resource | In the Anpheros lab connector |
|---|---|---|---|
| MSH | Separators, sending system, message type, message id | `MessageHeader` (or provenance) | Separators read from MSH; type checked for ORU^R01; message id kept for traceability |
| PID | Patient identifiers, name, birth date, sex | `Patient` | Not used: the patient is the one in the request URL, so a message cannot write into the wrong record |
| PV1 | Visit | `Encounter` | Not used |
| ORC / OBR | Order and report: filler/placer id, date | `ServiceRequest`, `DiagnosticReport` | OBR-3 (or OBR-2) is the report id, OBR-7 the default date |
| OBX | One result | `Observation` | One laboratory Observation per OBX |
| NTE | Free-text note | `Observation.note` | Not used |

## OBX field by field

| OBX field | FHIR Observation element | Notes |
|---|---|---|
| OBX-2 value type (NM, SN, ST, CWE) | choice of `value[x]` | NM and SN become `valueQuantity`; text stays text |
| OBX-3 identifier `code^text^system` | `code.coding` | `LN` in OBX-3.3 means LOINC; other systems are the lab's local code |
| OBX-5 value, OBX-6 unit | `valueQuantity.value`, `.unit` / `.code` (UCUM) | `<5` and `6,4` must be parsed deliberately |
| OBX-7 reference range | `referenceRange.low` / `.high` | `3.5-5.1`, `<200`, `>40` |
| OBX-8 abnormal flag | `interpretation` | H, L, HH, LL, A, N |
| OBX-11 result status | `status` | F → final, C → amended, P → preliminary, I → registered |
| OBX-14 observation time | `effectiveDateTime` | v2 times often lack a time zone; FHIR requires one |

## Convert a message with one request

```bash
curl -X POST "https://platform.anpheros.com/v1/patients/$PID/labs/import" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: x-application/hl7-v2+er7" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-binary @oru_r01.hl7
```

The answer lists how many Observations were created, how many were skipped as already imported, which markers could not be mapped, and the new Observations with their codes. Each one gets a stable identifier derived from the report, the test, the time and the value, so a laboratory that resends the same message creates no duplicates.

## Traps that break real integrations

1. **Time zones.** `20261002074500` has no offset; decide the sender's zone explicitly.
2. **Local codes.** Keep the lab's own code when there is no LOINC; never drop it.
3. **Resends.** Without a stable identifier per result, retries become duplicates.
4. **Corrections.** OBX-11 `C` is a correction; decide whether it replaces or adds, and mark the old result.
5. **Non-numeric values.** `positive`, `<5`, `6,4` need explicit rules, not a guess.

## What the connector does not do

It accepts ORU^R01 laboratory results over HTTPS. It does not receive ADT or order messages, does not speak MLLP over TCP (an interface engine in front can forward), does not create a DiagnosticReport, and does not match patients from PID.

## Frequently asked questions

### How do you map HL7 v2 to FHIR?
Segment by segment: PID to Patient, PV1 to Encounter, ORC/OBR to ServiceRequest and DiagnosticReport, OBX to Observation, NTE to notes. HL7's V2-to-FHIR implementation guide defines the field-level concept maps.

### Is there an HL7 v2 to FHIR converter?
Yes. Interface engines and open-source libraries convert messages; for laboratory results, the Anpheros lab connector converts an ORU^R01 message into FHIR R4 Observations in one HTTPS request and stores them in the patient's record.

### Which HL7 v2 message types does Anpheros accept?
ORU^R01 laboratory results. A message of another type gets a warning, and only its OBX segments are read; ADT, order and other messages are not supported.

### How are HL7 v2 abnormal flags represented in FHIR?
OBX-8 becomes `Observation.interpretation` using the HL7 ObservationInterpretation codes (H, L, HH, LL, A, N).

<!-- visual:cta-v2map -->

## Related

- [Lab results API: HL7 v2, FHIR and LOINC](https://developers.anpheros.com/guides/lab-results-api)
- [FHIR vs HL7 v2: practical differences](https://developers.anpheros.com/guides/fhir-vs-hl7-v2)
- [How to import laboratory results into a FHIR record](https://developers.anpheros.com/guides/import-lab-results-fhir)
- [HL7 v2 and FHIR for clinical dashboards](https://developers.anpheros.com/guides/clinical-dashboard-hl7-fhir)
- [Lab connector](https://developers.anpheros.com/guides/lab-connector)
