FHIR (Fast Healthcare Interoperability Resources) R4 is the foundational standard for modern healthcare data exchange. Published by HL7 International in 2019, Release 4 achieved "normative" status for its core resources, meaning the specification is stable and backward-compatible. For health IT teams integrating lab data, EHR systems, or clinical decision support, FHIR R4 is the protocol you will be building against.
This guide provides a comprehensive, implementation-focused walkthrough of FHIR R4. It covers the resources most relevant to laboratory data, walks through JSON structures, explains transaction patterns, addresses security, and describes real-world integration strategies. Whether you are building a FHIR facade over a legacy system or consuming FHIR output from an extraction API like MedExtract, this article gives you the technical foundation.
Introduction to FHIR R4
FHIR was designed to replace older HL7 standards (V2 messages, V3/CDA documents) with a web-native approach. Resources are the fundamental unit of data in FHIR. Each resource has a defined structure, a canonical URL, and a JSON or XML representation. FHIR servers expose RESTful endpoints where clients create, read, update, and delete resources using standard HTTP methods.
Why R4 specifically
FHIR has gone through multiple releases (DSTU 1, DSTU 2, STU 3, R4, R4B, R5). Release 4 is the version adopted by the overwhelming majority of production implementations worldwide. Key reasons include:
- Normative status: Core resource types (Patient, Observation, Bundle) are normative in R4, meaning they will not change in backward-incompatible ways.
- Regulatory adoption: The EU's EHDS regulation, US ONC rules (21st Century Cures Act), and national programs in Australia, Canada, and the UK all reference FHIR R4.
- Ecosystem maturity: SMART on FHIR apps, bulk data APIs, and implementation guides are all built and tested against R4.
- Vendor support: Every major EHR vendor (Epic, Cerner/Oracle Health, MEDITECH, Allscripts) exposes FHIR R4 endpoints.
FHIR vs. HL7 V2
Many healthcare systems still use HL7 V2 messages for lab data (ORU/OBR/OBX segments). While V2 is ubiquitous, it has fundamental limitations: no standard encoding (custom delimiters per site), no built-in security model, and no web-native API. FHIR R4 addresses all of these while providing a migration path from V2 through mapping guides maintained by HL7.
Key FHIR resources for lab data
Laboratory data in FHIR R4 is represented using a small set of interconnected resources.
Patient
The Patient resource identifies the individual whose lab results are being reported. At minimum, it contains a name and an identifier (such as a medical record number or national ID). In lab data exchange, the Patient is typically referenced by other resources rather than transmitted in full.
{
"resourceType": "Patient",
"id": "patient-1",
"identifier": [{
"system": "http://hospital.example.org/mrn",
"value": "MRN-12345"
}],
"name": [{
"family": "Garcia",
"given": ["Maria"]
}],
"gender": "female",
"birthDate": "1985-03-22"
}
Observation
The Observation resource is the workhorse of lab data. Each individual test result — a hemoglobin value, a glucose measurement, a white blood cell count — is represented as an Observation. The resource carries the LOINC code identifying the test, the result value, the unit of measurement, the reference range, and an interpretation flag.
{
"resourceType": "Observation",
"id": "obs-hgb-1",
"status": "final",
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "laboratory",
"display": "Laboratory"
}]
}],
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "718-7",
"display": "Hemoglobin [Mass/volume] in Blood"
}]
},
"subject": {
"reference": "Patient/patient-1"
},
"effectiveDateTime": "2026-03-01T08:30:00Z",
"valueQuantity": {
"value": 14.2,
"unit": "g/dL",
"system": "http://unitsofmeasure.org",
"code": "g/dL"
},
"referenceRange": [{
"low": { "value": 12.0, "unit": "g/dL" },
"high": { "value": 17.5, "unit": "g/dL" }
}],
"interpretation": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
"code": "N",
"display": "Normal"
}]
}]
}
DiagnosticReport
The DiagnosticReport resource represents the lab report as a whole. It groups multiple Observations, identifies the performing laboratory, and tracks the report's lifecycle status (partial, preliminary, final, amended). It is the entry point for consuming a complete lab result set.
{
"resourceType": "DiagnosticReport",
"id": "report-1",
"status": "final",
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0074",
"code": "LAB",
"display": "Laboratory"
}]
}],
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "58410-2",
"display": "CBC panel - Blood by Automated count"
}]
},
"subject": {
"reference": "Patient/patient-1"
},
"effectiveDateTime": "2026-03-01T08:30:00Z",
"issued": "2026-03-01T14:00:00Z",
"result": [
{ "reference": "Observation/obs-hgb-1" },
{ "reference": "Observation/obs-wbc-1" },
{ "reference": "Observation/obs-plt-1" }
]
}
Bundle
The Bundle resource is a container that holds a collection of other resources. For lab data, Bundles are used both for searching (search-set bundles) and for atomic data submission (transaction bundles). The Transaction Bundle is particularly important for lab data integration, as it ensures that a DiagnosticReport and all its referenced Observations are created together.
FHIR resource anatomy
Understanding the structure of FHIR resources is essential for correct implementation. Every resource shares a common anatomy.
Resource metadata
All resources have a resourceType field (required), an id (server-assigned), and optional meta containing version, last-updated timestamp, and profile declarations:
{
"resourceType": "Observation",
"id": "obs-123",
"meta": {
"versionId": "1",
"lastUpdated": "2026-03-01T14:00:00Z",
"profile": [
"http://hl7.org/fhir/StructureDefinition/Observation"
]
}
}
Coding and CodeableConcept
Clinical data elements in FHIR use the CodeableConcept type, which can carry multiple codings from different systems. For lab observations, the primary coding is typically LOINC, but local codes can be included as additional codings:
{
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "2345-7",
"display": "Glucose [Mass/volume] in Serum or Plasma"
},
{
"system": "http://hospital.example.org/local-codes",
"code": "GLU-SER",
"display": "Glucose serum"
}
],
"text": "Glucosa basal"
}
}
The text field preserves the original display text from the source document, which is valuable for auditing and troubleshooting.
References
Resources reference each other using the Reference type. References can be relative (Patient/patient-1), absolute (http://server.example.org/fhir/Patient/patient-1), or logical (using identifiers). In Transaction Bundles, temporary UUIDs (urn:uuid:...) are used to establish references between resources that do not yet have server-assigned IDs.
Extensions
FHIR provides a built-in extension mechanism for data elements not covered by the base specification. Extensions are identified by a URL and carry a typed value. Profiles define which extensions are expected or required for a given use case.
Transaction Bundles for atomic operations
Transaction Bundles are the primary mechanism for submitting a complete lab report to a FHIR server. The server processes all entries atomically: either all succeed or all fail.
Bundle structure
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"resource": {
"resourceType": "DiagnosticReport",
"status": "final",
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "58410-2",
"display": "CBC panel - Blood by Automated count"
}]
},
"subject": {
"reference": "Patient/patient-1"
},
"result": [
{ "reference": "urn:uuid:obs-hgb-uuid" },
{ "reference": "urn:uuid:obs-wbc-uuid" }
]
},
"request": {
"method": "POST",
"url": "DiagnosticReport"
}
},
{
"fullUrl": "urn:uuid:obs-hgb-uuid",
"resource": {
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "718-7",
"display": "Hemoglobin [Mass/volume] in Blood"
}]
},
"subject": {
"reference": "Patient/patient-1"
},
"valueQuantity": {
"value": 14.2,
"unit": "g/dL",
"system": "http://unitsofmeasure.org",
"code": "g/dL"
}
},
"request": {
"method": "POST",
"url": "Observation"
}
}
]
}
Key principles
- Temporary UUIDs: Use
urn:uuid:prefixed identifiers infullUrlandreferencefields. The server resolves these to real resource IDs after processing. - Request entries: Each entry includes a
requestobject specifying the HTTP method and resource type. POST creates new resources; PUT updates existing ones (using conditional references for idempotency). - Ordering: The server processes entries in order. Place referenced resources (Observations) before the resources that reference them (DiagnosticReport), or use
urn:uuid:references which the server resolves regardless of order. - Idempotency: Use conditional creates (
request.ifNoneExist) to prevent duplicate resource creation when the same lab report is submitted multiple times.
Batch vs. Transaction
FHIR distinguishes between batch and transaction bundle types. A transaction is atomic (all-or-nothing), while a batch processes each entry independently. For lab data, always prefer transaction to prevent partial ingestion that could leave orphaned Observations without a parent DiagnosticReport.
FHIR profiles and extensions
Base FHIR resources are intentionally broad. Profiles constrain them for specific use cases by defining required fields, restricting value sets, and declaring expected extensions.
Common lab data profiles
- US Core Laboratory Result Observation: Defines minimum data requirements for lab observations in the US context.
- International Patient Summary (IPS): Cross-jurisdictional profile that includes lab results as part of a patient summary.
- EU Laboratory Report: Profile aligned with the EHDS requirements for cross-border lab data exchange.
Declaring profile conformance
A resource declares which profiles it conforms to in its meta.profile array:
{
"meta": {
"profile": [
"http://hl7.eu/fhir/laboratory/StructureDefinition/Observation-resultslab-eu-lab"
]
}
}
Servers can validate incoming resources against declared profiles, rejecting non-conformant data.
Custom extensions for lab extraction
When generating FHIR output from an extraction pipeline, you may need extensions for metadata that the base spec does not cover:
- Extraction confidence: A numeric score indicating how confident the system is in the LOINC mapping.
- Source coordinates: Bounding box coordinates identifying where on the original document each value was extracted from.
- Matching stage: Which stage of the matching cascade produced the LOINC code (useful for auditing).
These are defined as extensions with a custom URL, for example:
{
"extension": [{
"url": "http://medextract.io/fhir/StructureDefinition/extraction-confidence",
"valueDecimal": 0.97
}]
}
Authentication and security
Healthcare data exchange requires robust security. FHIR specifies security mechanisms at multiple levels.
SMART on FHIR
SMART (Substitutable Medical Applications, Reusable Technologies) on FHIR is the dominant authorization framework for FHIR servers. It extends OAuth 2.0 with healthcare-specific scopes and launch contexts. A typical flow:
- The client application requests authorization scopes (e.g.,
patient/Observation.read,system/DiagnosticReport.write). - The authorization server authenticates the user or system and issues an access token.
- The client includes the access token in the
Authorizationheader of FHIR API requests. - The FHIR server validates the token and enforces the granted scopes.
Transport security
All FHIR exchanges must use TLS 1.2 or later. Mutual TLS (mTLS) is recommended for server-to-server integrations where both parties need to verify identity.
Audit logging
FHIR defines the AuditEvent resource for recording access to clinical data. Every read, create, update, and delete operation should generate an AuditEvent that captures who accessed what data and when. This is essential for GDPR compliance and for meeting the transparency requirements of the EHDS.
Data at rest
Servers storing FHIR resources must encrypt data at rest using AES-256 or equivalent. Access to encryption keys should follow the principle of least privilege and be managed through a dedicated key management service.
Error handling and validation
Robust error handling is critical for reliable FHIR integrations.
OperationOutcome
FHIR servers return errors using the OperationOutcome resource. Each issue includes a severity (fatal, error, warning, information), a code (invalid, required, not-supported, etc.), and a human-readable diagnostic message:
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "required",
"diagnostics": "Observation.code is required",
"location": ["Observation.code"]
}]
}
Validation strategies
- Schema validation: Verify that JSON structure matches the FHIR resource definition.
- Profile validation: Check conformance to declared profiles, including required fields and value set bindings.
- Business rule validation: Apply domain-specific rules (e.g., result value within plausibility range for the given LOINC code).
- Terminology validation: Verify that coded values exist in the referenced code systems (LOINC, SNOMED CT, UCUM).
The HL7 FHIR Validator (Java-based) is the reference implementation for validation. It can be run as a CLI tool, embedded in a server pipeline, or accessed through hosted services.
Handling partial failures
When a Transaction Bundle fails, the server rejects the entire bundle and returns an OperationOutcome explaining which entry caused the failure. The client should parse this response, fix the offending entry, and resubmit. Logging the full OperationOutcome is essential for debugging integration issues.
Real-world integration patterns
FHIR R4 deployments follow several common architectural patterns.
Pattern 1: FHIR facade
A FHIR facade sits in front of a legacy system (e.g., a LIS using proprietary protocols) and exposes its data through FHIR endpoints. The facade translates incoming FHIR requests into the legacy protocol and translates responses back into FHIR resources. This pattern is common during migration from HL7 V2 systems.
Pattern 2: Event-driven integration
Lab results trigger events that are published to a message broker (e.g., Kafka, NATS). Subscribers consume these events and process the FHIR Bundles — storing them in a data warehouse, sending them to an EHR, or triggering clinical decision support rules. This decoupled architecture scales well and handles variable throughput.
Pattern 3: Bulk data export
FHIR Bulk Data Access ($export operation) enables large-scale data extraction from FHIR servers. The server generates NDJSON files containing resources matching the requested criteria. This pattern is essential for analytics, quality reporting, and population health management.
Pattern 4: Extraction API integration
For organizations processing paper or PDF lab reports, the workflow starts with an extraction API. The API receives document images, performs OCR and LOINC mapping, and returns a FHIR Transaction Bundle. The receiving system submits this bundle to its FHIR server, where it becomes part of the patient's electronic record. This is the pattern MedExtract supports.
PDF/Image → MedExtract API → FHIR Bundle → FHIR Server → EHR
Pattern 5: Subscription notifications
FHIR R4 includes a Subscription mechanism where clients register interest in specific resource changes (e.g., "notify me when a new DiagnosticReport for patient X is created"). The server pushes notifications via webhooks or WebSocket channels. R5 introduces an improved topic-based subscription model, but R4 subscriptions remain widely deployed.
FHIR and the European Health Data Space (EHDS)
The European Health Data Space regulation, adopted by the European Parliament, mandates standardized exchange of health data across EU member states. Laboratory data is one of the priority categories.
EHDS requirements for lab data
- Standardized format: Lab results must be exchangeable in a standardized electronic format. FHIR R4 is the de facto implementation choice.
- Coded vocabulary: Observations must use LOINC codes. The regulation references the LOINC system explicitly.
- Cross-border exchange: Systems must support the MyHealth@EU infrastructure for cross-border data exchange.
- Patient access: Individuals have the right to access their health data in electronic format.
EU Lab Report profile
HL7 Europe has published the EU Laboratory Report Implementation Guide, which defines FHIR profiles specific to European lab data exchange. Key profiles include:
- EU Lab Observation: Extends base Observation with EU-specific value set bindings and mandatory coded results.
- EU Lab DiagnosticReport: Adds requirements for performing organization, result interpreter, and specimen information.
- EU Lab Bundle: Defines the structure for transmitting complete lab reports across borders.
Organizations building lab data systems for the European market should implement these profiles to ensure EHDS compliance.
Timeline and practical implications
EHDS implementation is phased across member states, with full operational requirements expected between 2028 and 2031. However, early adopters are already building FHIR-based infrastructure, and national sandbox environments are available for testing cross-border exchange. Starting with FHIR R4 now positions organizations to meet regulatory deadlines without major rework.
Building a FHIR-compliant lab data pipeline
Constructing a complete lab data pipeline from document input to FHIR output involves several stages, each with specific FHIR considerations.
Stage 1: Document processing
Accept lab reports in PDF, image, or electronic format. For paper-based reports, apply OCR with table detection and entity extraction. The output is structured data containing test names, values, units, and reference ranges.
Stage 2: LOINC mapping
Map extracted test names to LOINC codes using the multi-stage matching cascade described in our companion article. Each match includes a confidence score that can be surfaced in the FHIR output via an extension.
Stage 3: FHIR resource generation
Assemble the mapped data into FHIR resources:
- Create an Observation for each test result, populating
code(LOINC),valueQuantity(result + unit),referenceRange, andinterpretation. - Create a DiagnosticReport referencing all Observations, with appropriate
status,code, andissuedtimestamps. - Wrap everything in a Transaction Bundle with
urn:uuid:references.
Stage 4: Validation
Run the generated Bundle through a FHIR validator configured with the target profiles (base R4, EU Lab, or custom organizational profiles). Fix any validation errors before submission.
Stage 5: Submission
POST the Transaction Bundle to the target FHIR server endpoint ([base]/). Parse the response to extract server-assigned resource IDs. Handle errors by examining the OperationOutcome in the response.
Stage 6: Monitoring
Track submission success rates, validation error frequencies, and server response times. Set up alerts for failure patterns. Maintain an audit log of every bundle submitted and every response received.
Using the MedExtract API
MedExtract handles stages 1 through 3 in a single API call. You send a lab report document and receive a validated FHIR R4 Transaction Bundle. The API supports both the base R4 specification and EU Lab profiles, making it suitable for deployments across the European Health Data Space.
To get started:
- Review the API documentation for endpoint specifications
- Test with sample lab reports from your network
- Request a demo for a guided walkthrough
FHIR R4 provides the stable, interoperable foundation that healthcare data exchange requires. Combined with automated LOINC extraction, it enables a fully digital pipeline from paper lab report to structured, standards-compliant clinical data.
Related Articles
FHIR R4 Integration Guide for EHR Systems
A practical overview of integrating FHIR R4 resources into EHR systems, focusing on DiagnosticReport and Observation bundles from lab data.
Complete Guide to LOINC Code Extraction
Everything about automated LOINC code extraction from lab reports: process, challenges, dictionaries, and best practices.
FHIR DiagnosticReport Resource Explained
Everything about the FHIR R4 DiagnosticReport resource: structure, fields, profiles, and how it represents lab reports.