Healthcare ,

FHIR Integration Architecture Guide

REST, Bulk, Subscriptions, CDS Hooks, US Core profiling, SMART on FHIR auth, HL7 v2 mapping, server selection, validation pipelines, and production observability — the complete engineering playbook for building FHIR integrations that survive real healthcare environments.

FHIR Integration Architecture Guide

  • Last Updated on May 19, 2026
  • 28 min read

FHIR is not an interface. It is an architectural philosophy — one that determines how your data model, API surface, auth layer, and integration topology must all fit together to achieve real interoperability.

450+

FHIR resource types in R4 — most teams use fewer than 30

Faster integration delivery with pre-built FHIR middleware vs. custom mapping

80%

Of EHR vendors now expose FHIR R4 APIs — Epic, Cerner, Athenahealth, eCW

Chapter 1. FHIR Architecture Decision Map

Every FHIR integration begins with three architecture decisions that constrain every subsequent choice. Teams that make these decisions explicitly — before writing integration code — build systems that scale. Teams that defer them build systems that require expensive rewrites.

  1. FHIR version contract: R4 is the current mandated baseline under the ONC 21st Century Cures Act and CMS Interoperability Rule. R4B introduced breaking changes to a small set of resources (Citation, Evidence, MedicationKnowledge). R5 is published but not yet required. Declare your target version in a CapabilityStatement before any other technical decision — it governs resource structure, search parameter availability, and terminology binding behavior across the entire integration surface.

  2. Integration topology: Point-to-point (your app queries the EHR's FHIR endpoint directly), Hub-and-spoke (a central FHIR server aggregates data from multiple source systems), or Event-driven (Subscriptions or Kafka push data to consumers asynchronously). Each has different latency, consistency, and operational complexity profiles. The right topology depends on your use case — not on convention.

  3. Profile conformance tier: Base FHIR (no constraints — maximum flexibility, minimum interoperability), US Core (the ONC-mandated baseline for US data exchange — must-support elements, required terminologies), or Implementation Guide–specific (Da Vinci, Argonaut, mCODE, QI-Core — use-case-specific constraints that build on US Core). Declare your conformance tier in your CapabilityStatement and enforce it with a validation pipeline from day one.

⚠️ Architecture Trap

The "we'll add FHIR profiling later" decision costs 4–6× more than doing it at project start. US Core profiles constrain cardinality (making optional fields required), restrict value sets (narrowing polymorphic types), and enforce must-support semantics. Retrofitting these constraints onto an existing data pipeline means re-mapping, re-validating, and often re-collecting data that was captured in non-conformant formats.

Chapter 2. REST vs Bulk vs Subscriptions

FHIR defines three primary interaction paradigms, each optimized for a different data access pattern. Choosing the wrong paradigm for a use case is one of the most common FHIR architecture mistakes — and one of the easiest to avoid.

🔍

FHIR REST API

Point-in-Time Reads

Synchronous CRUD + Search. Best for: patient-context queries at point-of-care, lookup-driven workflows, app launch (SMART), CDS Hooks data requirements. Not for: bulk data extraction or event-driven notifications.

📦

FHIR Bulk Data ($export)

Population-Scale Export

Async NDJSON export via Group/$export or Patient/$export. Best for: analytics, quality reporting, population health, data warehouse ingestion, payer data pulls. Not for: real-time or patient-context use cases.

📡

FHIR Subscriptions

Event-Driven Push

Topic-based push notifications when resources change. R4: Subscription resource (limited). R5: SubscriptionTopic + SubscriptionStatus (full event streaming). Best for: care alerts, downstream system sync, real-time dashboards.

🧠

CDS Hooks

Workflow-Embedded AI/Logic

FHIR-adjacent spec for embedding decision support into EHR workflow at clinical hook points (patient-view, order-sign, medication-prescribe, encounter-start). Returns Cards and Actions displayed in EHR UI. Best for: clinical alerts, PA pre-check, care gap surfacing.

💡Architecture Pattern

Most production FHIR architectures use all four paradigms simultaneously — REST for point-of-care app queries, Bulk for nightly analytics sync, Subscriptions for care event alerting, and CDS Hooks for clinical workflow integration. The mistake is trying to force one paradigm to serve all four use cases.

Read more: 10 FHIR Integration Architecture Mistakes That Delay HealthTech Products

Chapter 3. US Core Profiling & StructureDefinitions

Base FHIR resources are deliberately under-constrained — they must serve every healthcare system globally. US Core tightens that contract for the US regulatory context, and Implementation Guide-specific profiles tighten it further for specific use cases. Your architecture must decide which constraint layer is authoritative for each resource type you exchange.

Resource TypeBase FHIRUS Core 6.1Da Vinci (Prior Auth)mCODE (Oncology)
Patientname 0..name 1.. (must-support)Inherits US CoreInherits US Core
Conditioncode 0..1code 1..1 ICD-10/SNOMEDExtends for PA contextPrimary Cancer Condition profile
Observation (Lab)value[x] 0..1, any type

LOINC code required, valueQuantity preferred

Inherits US CoreTumor Marker profile
MedicationRequestmedication[x] 1..1

RxNorm code required, dosage must-support

PA medication profile with prior auth extension

Cancer-related medication profile

CoverageNo must-support requirementsLimited must-support

HRex Coverage profile — full must-support set

Not covered

Spec Reference

US Core 6.1.0 (January 2024) is the current ONC-certified baseline for USCDI v3. It adds 10 new profiles including Average Blood Pressure, Care Experience Preference, and Specimen. Your CapabilityStatement should declare.

Peerbits Services - EHR Integration Services | HL7, FHIR & API Healthcare Integration

Chapter 4. SMART on FHIR Auth Architecture

SMART on FHIR is the OAuth 2.0-based authorization framework that governs how applications request and receive scoped access to FHIR resources. SMART v2 (aligned with FHIR R4, required by ONC's HTI-1 rule) introduced asymmetric backend authentication, granular resource-level scopes, and launch context extensions that SMART v1 lacked.

Two Launch Flows SMART defines two primary launch patterns, each suited to a different integration context:

EHR Launch (Patient Context)

EHR initiates app launch with patient context embedded in launch token. App receives patient_id, encounter_id, user identity from EHR. Used for clinician-facing apps embedded in EHR workflow.

Smart Token With Context

Access token includes fhirContext claim with Patient/{id} reference. All FHIR queries are automatically patient-scoped. App never needs to ask "which patient?"

Backend Services (M2M)

Server-to-server integration with no user context. App authenticates using a client_assertion JWT signed with a private key (RS384 or ES384). Used for bulk data pulls, analytics pipelines, system-level operations.

System-Level Access Token

Token granted for system/* scopes. No user context. Must be narrowed to minimum necessary system scopes — never system/. in production. Token lifetime: 5 minutes (never cache beyond expiry).

SMART v2 — Backend Services JWT Assertion

ONC HTI-1 Required

// Step 1: Build JWT client assertion (signed — RS384 or ES384 ONLY) // HS256 is NOT acceptable for SMART v2 Backend Services const clientAssertion = { "iss": "https://your-app.example.com", // Must match registered client_id "sub": "your_client_id", // Same as iss for Backend Services "aud": "https://ehr.example.com/oauth2/token", // EHR token endpoint "jti": crypto.randomUUID(), // Unique per request — prevents replay "exp": Math.floor(Date.now() / 1000) + 300 // Max 5 minutes }; // Sign with RS384 private key (JWKS public key registered with EHR at onboarding) // Step 2: Exchange assertion for access token POST /oauth2/token grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer client_assertion=<signed-jwt> scope=system/Patient.read system/Observation.read // Minimum necessary, explicit types # NEVER: scope=system/*.read # Wildcard rejected by major EHRs, violates minimum necessary

Peerbits Services - SMART on FHIR App Development

Chapter 5. Hub-and-Spoke vs Event-Driven Topologies

FHIR integration topology — how your systems are wired together — determines your latency profile, consistency guarantees, and operational complexity at scale. Three topologies cover the vast majority of real-world healthcare integration architectures:

Topology 1 — Direct REST (Point-to-Point)

App / Consumer

Issues FHIR GET/POST against source EHR FHIR endpoint directly via SMART access token

EHR FHIR API

Epic Sandbox / Cerner / Athena FHIR R4 endpoint responds synchronously

Use when: Single source system, patient-context queries, low data volume. Avoid when: Multiple source EHRs, offline resilience required, high query volume that may hit EHR rate limits.

Topology 2 — FHIR Aggregation Hub

EHR A (Epic)

FHIR R4

EHR B (Cerner)

FHIR R4

FHIR Hub / MPI

Normalises, de-dupes, patient matches. HAPI FHIR / Azure HDS / HealthLake

All Consumers

Apps, Analytics, Payers, CDS

Use when: Multiple source systems, patient matching across organizations, consumers need a single FHIR endpoint regardless of source. Hub must implement a Master Patient Index (MPI) for cross-system patient identity resolution.

Topology 3 — Event-Driven FHIR Pipeline

EHR / Source

Fires FHIR Subscription notification on resource change event

Event Bus

Kafka / Azure Event Hub / AWS EventBridge. FHIR payload or reference-only notification

Consumers

Care management apps, alerting systems, analytics sinks, downstream FHIR servers

Use when: Real-time alerting (admit/discharge/transfer), downstream system synchronization, care gap notification, population health event streaming. Note: FHIR R5 Subscriptions (SubscriptionTopic model) are significantly more capable than R4's Subscription resource — architect for R5 compatibility if building new.

Chapter 6. HAPI vs Azure HDS vs AWS HealthLake

The FHIR server you choose determines your operational overhead, conformance ceiling, performance floor, and vendor lock-in exposure. There is no universally correct answer — only the right server for your specific deployment context.

TypeR4 ConformanceR5 ReadinessBest ForWatch Out
HAPI FHIRFull R4 + R4BR5 support in 7.x

Full control, custom extensions, on-prem/hybrid

Operational burden. Performance tuning required at scale.

Azure Health Data ServicesStrong R4 conformanceLimited R5 preview

Azure-native stacks, HIPAA BAA, managed ops

Azure vendor dependency. Custom search params limited.

AWS HealthLakeR4 with NLP extractionNo R5 roadmap public

AWS-native, built-in NLP, analytics integration

Limited FHIR search expressiveness. Higher per-resource cost.

Google Cloud Healthcare APIR4 conformanceR5 in roadmap

GCP-native, DICOM + FHIR in one service, BigQuery integration

Smaller healthcare ecosystem. Less community tooling.

MedplumStrong R4Active R5 work

Digital health startups, fast iteration, full-stack FHIR

Younger ecosystem. Enterprise support less mature.

Firely ServerFull R4 + R4BR5 production

Highest conformance fidelity, IG publication, EU market

Commercial licensing cost. Less North America footprint.

🧭Decision Framework

If you are building a greenfield digital health product on AWS, start with HealthLake for data storage and HAPI FHIR as your API layer. If you are building a health system integration hub on Azure, use Azure Health Data Services. If you need maximum FHIR conformance and custom profile support, HAPI FHIR or Firely Server are the only options that give you full IG customization at every layer.

Chapter 7. HL7 v2 to FHIR R4 Mapping Architecture

The majority of production healthcare data still arrives as HL7 v2 messages — the dominant standard in labs, ADT feeds, radiology, and pharmacy systems built before FHIR existed. A FHIR architecture that ignores v2 is incomplete. HL7 v2-to-FHIR mapping is neither a one-time ETL job nor a library call — it is an ongoing architectural concern because:

  • v2 is implementation-specific. HL7 v2 has dozens of optional fields, custom Z-segments, and per-institution variations. "ADT A01" from Hospital A is structurally different from "ADT A01" from Hospital B. Your mapping layer must be per-source-system configurable, not a single global mapping function.

  • v2 and FHIR have incompatible identity models. v2 uses string identifiers in MSH, PID, PV1 segments. FHIR uses resource references (Patient/123, Encounter/456). Your mapping layer must resolve v2 identifiers to FHIR resource IDs — which requires a running FHIR server to look up or create the referenced resources, not just a field mapping table.

  • v2 terminology ≠ FHIR terminology. v2 uses local codes, NCI codes, LOINC, SNOMED, and proprietary lab codes interchangeably in the same segment. FHIR profiles mandate specific code systems per element. Every v2-to-FHIR mapping must include a terminology translation layer backed by a live terminology service.

FHIRPATH API — ENCOUNTER SEARCHSET LIBRARYSYNTAX OK
// API to AUTH (table) + FHIR Encounter

// next: provides account-identity (patient clinical data

function auxAuth(patIdEncounter,cRef,transMetaSpec) {

  const ptd = uIntg.getAsObject('PEM'),
        par = uIntg.getAsObject('PAT');

  // Slot 1: Slice over encounter resources
  const pattern = await fetchClient.resolveResourceDataSet({
    localIdentifier: { system: ptd.getProfileId(); analyzeValue.ptd.getField(42) ]
  });

  // Slot 2: Translate PII (clinician type) is FHIR Encounter.type,
  //        and partition (patId:orgId:site:authz_ami)
  const classCode = await terminologyService.translate({
    source: "http://fhir/admin-type",
    target: "http://terminology.hl7.org/CodeSystem/v3-ActCode"
  });

  // Slot 3: Build Encounter resource (us Core Encounter profile)
  return {
    resourceType: 'Encounter',
    status: 'in-progress',
    class: { system: classCode, code: par.getField(42) },  // ← slot - in progress
    subject: { reference: 'Patient/[patId]', analytics: 'value: ptd.getField(99) ]
    period: { start: ptd.getFieldId(45) },
    identifier: [{ system: 'urn:oid:your-urg-oid', value: ptd.getField(49) }]
  };
}

Recommended mapping tooling: HL7's official v2-to-FHIR mapping tables (published as a FHIR Implementation Guide at hl7.org/fhir/uv/v2mappings) are the canonical reference. LinuxForHealth HL7v2-FHIR Converter (open source) provides production-grade Java-based mapping. Microsoft FHIR Converter supports v2, C-CDA, and custom Liquid templates for Azure-native stacks.

Chapter 8. Terminology Service Architecture

Clinical terminology is the connective tissue of FHIR interoperability. FHIR resources encode clinical meaning through coded concepts — LOINC for lab tests and observations, SNOMED CT for clinical findings, RxNorm for medications, ICD-10-CM for diagnoses, CPT for procedures. These code systems are large (SNOMED CT has 350,000+ concepts), versioned (updated quarterly/annually), licensed (CPT requires AMA license), and interdependent (ICD-10 maps to SNOMED maps to LOINC).

The correct architecture treats your FHIR terminology service as shared infrastructure — a dedicated microservice that all FHIR applications call for code validation and cross-system translation, not a library bundled into each service:

FHIR Application

Needs to validate Observation.code is a valid LOINC lab code

Terminology Service

$validate-code / $translate / $expand operations. HAPI FHIR with terminology pack, Ontoserver, or TerminologyServer.net

Code System Store

LOINC, SNOMED CT, RxNorm, ICD-10 — versioned, cached, updated on release schedule

Hardcoded Terminology

Each service maintains its own static copy of LOINC codes as a lookup table in its database. ICD-10 updated annually in October — services diverge on code versions. RxNorm NDC mappings stale within weeks. Translation logic duplicated across 6 services with 6 different bug sets.

Terminology Service Pattern

Single shared terminology service exposes FHIR $validate-code, $translate, and $expand endpoints. ValueSet expansions cached with configurable TTL. Version-aware — services can request code validation against a specific code system version. Updates propagated once, used everywhere.

Chapter 9. Clinical Decision Support At the Point of Care

CDS Hooks is the FHIR-aligned specification for embedding clinical decision support into EHR workflow at real-time, point-of-care hook points. It closes the loop between your FHIR data layer and the clinical UI where physicians and nurses make decisions. A FHIR architecture without CDS Hooks delivers data — a FHIR architecture with CDS Hooks delivers intelligence.

Hook PointFires WhenFHIR Prefetch ContextHigh-Value Use Cases
patient-viewClinician opens patient chart

Patient, Condition, MedicationRequest

Care gaps, chronic care enrollment (CCM/RPM), risk scores, outstanding PAs

order-select

Clinician selects an order but before signing

Patient, draft MedicationRequest/ServiceRequest

PA coverage check, formulary guidance, duplicate order alert

order-sign

Clinician signs an order (final)

Patient, signed MedicationRequest/ServiceRequest

Final PA eligibility, drug-drug interaction check, dosing alert

encounter-startNew encounter created

Patient, Encounter, Condition

CCM eligibility alert, care plan reminder, preventive care due

encounter-dischargeInpatient discharge initiated

Patient, Encounter, Condition

Transition of care checklist, readmission risk score, follow-up scheduling

Peerbits Services - AI Prior Authorization Automation

Chapter 10. FHIR Validation Pipeline Design

Accepting malformed FHIR resources silently is the most insidious form of data quality degradation in healthcare integration. A Condition resource with a code from the wrong code system is structurally valid — it will pass JSON parsing — but it will fail profile validation and produce incorrect clinical data downstream. Your FHIR architecture must include a multi-layer validation pipeline that runs on every inbound resource before it reaches your data store.

Layer 1 — Structural

JSON/XML well-formedness. FHIR base resource validation. Required fields. Correct data types. Cardinality constraints. Run: HAPI FHIR Validator or HL7 Validator CLI

Layer 2 — Profile

StructureDefinition conformance. Must-support element presence. FHIRPath invariant rules. Slice validation. US Core / IG conformance. Run: same validator + loaded IGs

Layer 3 — Terminology

Code system membership ($validate-code). ValueSet binding enforcement. Required vs preferred vs extensible binding. Run: Terminology Service $validate-code operation

Layer 4 — Business Rules

Clinical plausibility checks. Referential integrity within Bundles. Organization-specific rules not encodable in profiles. Run: Custom FHIRPath rules or rule engine

Dead Letter Queue

Validation failures routed here. Never silently dropped. Never auto-corrected. Human review required. Failure taxonomy logged for source system improvement feedback.

💡Production Pattern

Run Layer 1–2 validation synchronously in the request path for FHIR REST interactions — return an OperationOutcome with validation errors in the HTTP response body. Run Layer 3–4 asynchronously post-accept for bulk ingestion pipelines where synchronous terminology lookup would introduce unacceptable latency.

Chapter 11. Production FHIR Monitoring

Standard HTTP monitoring misses most FHIR-specific failure modes. A FHIR server that returns HTTP 200 with an OperationOutcome resource containing errors is succeeding at HTTP and failing at FHIR simultaneously. A Bulk export job that returns 202 Accepted and then silently fails midway through generating output files leaves no visible HTTP error. Your observability stack must understand FHIR semantics — not just HTTP semantics.

FHIR-Specific Metrics to Instrument

  • OperationOutcome error rate by resource type and issue code. Track the percentage of FHIR responses containing OperationOutcome resources with severity "error" or "fatal" — broken out by resource type (Patient, Observation, MedicationRequest) and issue code (required, value, invalid). This is your data quality leading indicator.

  • FHIR search result-set distribution. Track p50/p95/p99 result counts per search operation type. A sudden shift toward zero-result searches for a parameter that normally returns results indicates a bug in search parameter handling or a source data quality regression — not a legitimate empty result set.

  • Bulk export job completion rate and NDJSON file integrity. Track the percentage of $export jobs that complete vs. fail vs. expire. For completed jobs, validate NDJSON file line counts against expected population size. A completed export with 10% fewer lines than expected is a silent data loss event.

  • SMART token grant failure rate by error type. Distinguish between invalid_client (key registration issue), invalid_scope (scope not permitted), and server errors. Token grant failures are clinical access failures — they must alert, not just log.

  • Terminology validation cache hit rate and error rate. A terminology cache miss on a required code system (LOINC unavailable) that causes validation to fail silently is a production incident. Track terminology service availability separately from FHIR server availability.

Chapter 12. FHIR R5 Migration Readiness

FHIR R5 was published in March 2023. While no major regulatory mandate requires R5 adoption today, Epic's Sandbox, Firely Server, and HAPI FHIR 7.x already expose R5 endpoints. CMS Interoperability rulemaking for 2026+ is expected to reference R5 or R5-aligned IGs. Building R5 readiness into your architecture now costs significantly less than migrating under regulatory pressure later.

Breaking Changes from R4 to R5 That Affect Most Integrations

AreaR4 BehaviorR5 ChangeMigration Complexity
Subscriptions

Subscription resource (limited topic support)

SubscriptionTopic + SubscriptionStatus — full event streaming model

High — complete architectural redesign of event pipeline

VersionIndependent References

Reference.reference is a URL string

Reference.identifier added as canonical alternative

Medium — update reference resolution logic

MedicationRequest

medication[x] polymorphic

medication CodeableReference — more expressive

Medium — update medication reference handling

AuditEvent

AuditEvent resource (limited structure)

Significantly restructured for ATNA alignment

High — rebuild audit logging pipeline

CapabilityStatement

CapabilityStatement.rest

Minor additions — backward compatible

Low — additive changes only

🔭R5 Readiness Recommendation

Build your FHIR version negotiation layer now — every client request should declare Accept: application/fhir+json; fhirVersion=4.0 explicitly. Your FHIR server should respond with the version it served from the Content-Type header. This makes a future version migration a routing configuration change, not a client application rebuild. If you are building a new Subscriptions pipeline, implement the R5 SubscriptionTopic model from the start — HAPI FHIR 7.x supports it in R4 compatibility mode.

Start With Architecture, Not Configuration

Every FHIR integration that collapses at scale made its fatal decisions in the first two weeks — wrong version contract, wrong topology, wrong profile tier, wrong server. Peerbits has architected FHIR integration stacks across Epic, Cerner, Oracle Health, Athenahealth, and eClinicalWorks environments, from single-source point-of-care apps to multi-EHR population health hubs serving millions of patients.

Our FHIR Architecture Review is a 5-day engagement delivering a full integration stack assessment, CapabilityStatement gap analysis, US Core conformance scorecard, and a documented architecture decision record (ADR) set for your engineering team. Delivered as a written report with a prioritized implementation roadmap.

Book Free FHIR Architecture Review
author-profile

Ubaid Pisuwala

Ubaid Pisuwala is a highly regarded healthtech expert and Co-founder of Peerbits. He possesses extensive experience in entrepreneurship, business strategy formulation, and team management. With a proven track record of establishing strong corporate relationships, Ubaid is a dynamic leader and innovator in the healthtech industry.

Related Post

Award Partner Certification Logo
Award Partner Certification Logo
Award Partner Certification Logo
Award Partner Certification Logo
Award Partner Certification Logo