Healthcare Integration-9 min read

HL7 v2 to FHIR terminology: OBX to Observation with LOINC and SNOMED

Map a de-identified ORU/OBX fragment onto Observation.code and value[x] using HL7 v2-to-FHIR 1.0.0. LOINC binds observations; SNOMED binds problems and allergies as the IG maps them. Local codes fail first, not PID.

Ala Ben Aicha

HL7 v2 to FHIR terminology: OBX to Observation with LOINC and SNOMED

Direct answer

Map OBX to Observation using the v2-to-FHIR IG 1.0.0: OBX-3 becomes Observation.code, OBX-5 becomes value[x]. Bind LOINC on observations and SNOMED on problems and allergies. Local codes, not PID, are the usual failure.

Pin the published maps, then the bindings

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). Prefer that package over the CI build. The hybrid engine pattern is the v2-to-FHIR migration playbook; the order/result choreography is the radiology and lab workflow. This page is the terminology contract inside that engine.

The segment map to pin is OBX → Observation. Problems and allergies are not OBX: the IG maps AL1 → AllergyIntolerance (AL1-3AllergyIntolerance.code) and DG1 → Condition (DG1-3Condition.code), also via EpisodeOfCare.diagnosis.

v2 field FHIR path Binding / type map Usual failure
OBX-3 Observation Identifier (CWE) Observation.code LOINC http://loinc.org when CWE.3 is LN Local mnemonic (HGB^^^L) with no system
OBX-2 + OBX-5 value[x] NM → valueQuantity; ST/FT/TX → valueString; CWE/CE/CNE/CF → valueCodeableConcept Value type and value[x] disagree
OBX-6 Units valueQuantity unit/code UCUM when the sender actually sends it Unit on the string, not on the Quantity
OBX-11 Result status Observation.status Table 0085 → status (Ffinal) Treating C (corrected) as a new Observation
AL1-3 Allergen AllergyIntolerance.code SNOMED CT when CWE.3 is SCT Free-text allergen with no code system
DG1-3 Diagnosis Condition.code SNOMED CT (or the national diagnosis system the CWE names) as the IG maps CWE Assuming every DG1 is a problem-list Condition without reading the message map

LOINC and SNOMED are bindings. They are not a licence I sell, not a code-system I host, and not implied by a valid FHIR JSON document. The v2-to-FHIR IG maps CWE → CodeableConcept; it does not translate a local table into LOINC or SNOMED for you.

Primary sources: v2-to-FHIR 1.0.0, OBX → Observation ConceptMap, LOINC.

Identifier on the observation: OBX-3, not PID

PID still becomes Patient — that is the ADT article. Terminology failures show up when OBX-3 has no assigning coding system. A second Patient is the wrong fix.

De-identified ORU/OBX fragment (specification fixture, not a person):

MSH|^~\&|LIS|LAB-A|FHIR-BRIDGE|HOSP-A|20260919120000||ORU^R01^ORU_R01|MSG0007|P|2.5
PID|1||HOSP-MRN-0001^^^HOSP-A^MR||EXAMPLE^JANE^Q
OBR|1||FILL-2026-0042|58410-2^CBC panel - Blood by Automated count^LN
OBX|1|NM|718-7^Hemoglobin [Mass/volume] in Blood^LN||13.2|g/dL|12.0-16.0|N|||F

Projected Observation (truncated):

{
  "resourceType": "Observation",
  "status": "final",
  "code": {
    "coding": [
      {
        "system": "http://loinc.org",
        "code": "718-7",
        "display": "Hemoglobin [Mass/volume] in Blood"
      }
    ]
  },
  "valueQuantity": {
    "value": 13.2,
    "unit": "g/dL",
    "system": "http://unitsofmeasure.org",
    "code": "g/dL"
  }
}

The local-code variant OBX|1|NM|HGB^Hemoglobin^^L||13.2|g/dL parses as v2 and as FHIR and still fails every semantic check that expects LOINC. That is the usual production defect — not a missing PID-3.

What to implement first

  1. Inventory OBX-3 coding systems on real de-identified messages (LN, SCT, local L, empty). Count how many Observation.code values would have no system.
  2. Pin hl7.fhir.uv.v2mappings#1.0.0. Implement OBX → Observation including OBX-2 → value[x] branching; do not hard-code valueQuantity for every OBX.
  3. Bind LOINC on lab/clinical observations and SNOMED CT on AL1/DG1 as the IG maps those segments. Keep national code systems as additional coding entries; do not drop them.
  4. Test corrections (OBX-11 = C) and cancels, not only the happy-path F. Report context still needs DiagnosticReport where the radiology/lab guide says so.

What this is not

This article is not a LOINC or SNOMED CT licence, not a UMLS subscription, not a patient-identity matcher, and not clinical advice. Mapping one OBX in a lab does not certify an interface. I do not sell terminology licences. PID mismatches belong on the ADT/MPI pages. Values above are fixtures, not a person.

Related reading

For engine work that preserves OBX-3 systems into Observation.code, use HL7 FHIR integration or start a project.

HL7 v2FHIROBXObservationLOINCSNOMEDORUTerminology

Related reading and services

Let's Continue the Conversation

Have questions about this topic? I'd love to hear from you.

Get in Touch

🍪 Do you like cookies?

Allow analytics cookies to help understand site visits and enquiries? Optional analytics stays off until you accept.

Learn More