FHIR Is Not Enough: Real-Time Integrations Still Need HL7v2

FHIR answers 'what does this patient look like now?' To ask for changes you'll have to remember how HL7v2 works.

the nighthawk · 10 min read · 2026-04-02


Here's something that catches almost every FHIR-first startup off guard: you cannot get push notifications from a major EHR using FHIR.

You can query patients. You can read encounters, conditions, medications, observations — the full clinical picture. FHIR is excellent at structured data access. But when you need to know when a patient gets admitted, when a lab result comes back, when a medication gets ordered — FHIR has no production-ready answer.

The spec has something called Subscriptions. Almost nobody implements it. The gap between what the spec promises and what vendors actually ship is where most real-time integration plans go to die. (If you need a primer on how FHIR fits into the broader standards landscape, start with the 101.)

The Spec Nobody Implements

FHIR R4 includes a Subscription resource. In theory, you create a Subscription that says "notify me when a new Encounter is created for Patient X" and the server pushes an event to your webhook. Clean. RESTful. Modern.

In practice, R4 Subscriptions have serious limitations. There's no way to detect state transitions — you can't say "notify me when an Encounter status changes from planned to in-progress." There's no heartbeat mechanism to confirm your channel is still alive. There's no way to subscribe to resource deletions. The filtering is primitive.

The FHIR community knew this. FHIR R5 completely redesigned the Subscription system, splitting it into three resources:

This is a much better design. It's also not what anyone is running in production.

The Backport

Because R5 adoption is years away for most EHR vendors, HL7 published the R5 Subscriptions Backport IG (STU 1.1.0, January 2023). This brings the R5 Subscription model to R4 and R4B servers via an implementation guide — no full R5 upgrade required.

It's the right idea. The vendor adoption tells the real story:

EHR Vendor FHIR Subscriptions Support
Epic Not supported. Recommends HL7v2 via Bridges.
Oracle Health (Cerner) Limited. Recommends HL7v2 COI for real-time.
MEDITECH Not supported.
athenahealth R5 Backport — 20+ topics. Alpha.

athenahealth is the only major vendor implementing the backport, and it's still in alpha. Everyone else either doesn't support FHIR Subscriptions at all or supports them in such a limited way that you can't build a production workflow on them.

The Polling Trap

If the server won't push events to you, the alternative is polling: hit the FHIR API on a schedule and check if anything changed.

GET /Encounter?patient=Patient/123&date=ge2026-02-28&_sort=-date

This works for a demo. It does not work at scale.

The math is straightforward. Say you're monitoring 10,000 patients for admission events and you need sub-minute latency. That's 10,000 API calls per minute. At 30-second intervals it's 20,000. Each call hits the EHR's FHIR API, which has rate limits — Epic's non-production environments cap at 5 requests per second. In production you get more headroom, but not "poll 10,000 patients every 30 seconds" headroom.

You'll hit HTTP 429 rate limits. You'll eat CPU cycles parsing responses that say "nothing changed" 99% of the time. And you'll still have anywhere from 0 to 60 seconds of latency depending on where in the polling cycle the event lands.

Some teams try to optimize this with _lastUpdated queries or _history operations, but these have their own quirks across vendors — not all servers support them consistently, and the semantics of "last updated" can vary.

Polling is a trap because it almost works in development. Then it falls apart in production under real patient volumes and rate limits.

What Epic Actually Wants

Epic is the dominant EHR in the US, covering over 35% of US hospital beds. If you're building a clinical integration, chances are you're integrating with Epic.

Epic's recommended architecture for real-time event notification is HL7v2 messages delivered via Epic Bridges.

Epic Bridges is an interface engine that sends HL7v2 messages — ADT (Admit/Discharge/Transfer), ORM (orders), ORU (results) — over TCP connections using the MLLP protocol. When a patient is admitted, Bridges fires an ADT^A01 message. When a lab result is finalized, it sends an ORU^R01. These messages arrive in near real-time, typically within seconds of the clinical event.

This is Epic's production integration pattern in 2026. Epic is aware of the FHIR Subscription gap — they submitted public comments on the Federal FHIR Action Plan in November 2024 explicitly advocating for the R5 Backport IG. But until they implement it themselves, Bridges is what you get.

The hybrid architecture looks like this:

┌─────────────┐
│   Epic EHR   │
└──────┬───────┘
       │
       ├──── HL7v2 (Bridges) ───→ Integration Engine ───→ Your App
       │     ADT^A01, ORU^R01     (Mirth / Rhapsody)     (knows WHEN)
       │     "Patient admitted"
       │     "Lab result ready"
       │
       └──── FHIR R4 API ←──── Targeted Query ←───────── Your App
             GET /Patient/123                              (gets WHAT)
             GET /Observation?...

HL7v2 tells you when. An ADT message arrives the moment a patient is admitted. It contains enough identifiers — MRN, encounter ID, patient class — to know what happened and to whom.

FHIR tells you what. Once you know something changed, you make targeted FHIR queries to pull the structured clinical data you need. Patient demographics, encounter details, lab results, medications — all in clean FHIR JSON with standardized coding.

This is actually good architecture. Each protocol does what it's best at: HL7v2 provides low-latency event delivery over persistent TCP connections, and FHIR provides structured, queryable data access over REST.

The Integration Engine Layer

You might have noticed the box in the middle of that diagram: the integration engine. This is a piece you can't skip.

HL7v2 messages arrive over MLLP (Minimal Lower Layer Protocol) — a TCP-based protocol with start-of-block and end-of-block characters wrapping each message. The messages themselves are pipe-delimited segments that look like this:

MSH|^~\&|EPIC|HOSPITAL|YOURAPP|YOURORG|20260228120000||ADT^A01|MSG001|P|2.5.1
EVN|A01|20260228120000
PID|1||MRN12345^^^EPIC^MR||DOE^JOHN^A||19800115|M|||123 MAIN ST^^ANYTOWN^NY^12345
PV1|1|I|4EAST^402^A|||||||MED||||||||E123456^^^EPIC^VN|||||||||||||||||||||20260228115500

You need something to receive these messages, parse them, route them, and potentially transform them before your application sees them. That's what Mirth Connect, Rhapsody, or Microsoft Azure Health Data Services do. They're integration engines (sometimes called interface engines) that speak HL7v2/MLLP natively and can translate, filter, and route messages to downstream systems.

For startups, this is often the unexpected line item. You budgeted for FHIR API integration — REST calls, OAuth tokens, JSON parsing. You did not budget for standing up an integration engine, managing MLLP connections, parsing HL7v2 segments, and handling persistent TCP connections that need monitoring, reconnection logic, and message acknowledgment. (If you've never seen an HL7v2 message before, go look at the pipe-delimited example above and imagine debugging that at 2am.)

Mirth Connect (now NextGen Connect) is open source and the most common choice for smaller teams. It handles HL7v2 parsing, message routing, and transformation with a visual interface. But it's another service to deploy, configure, and keep running.

Why This Matters for Startups

If you're building a clinical application that needs to react to events in real-time — patient admissions, discharge notifications, order alerts, result delivery — you're building a hybrid integration whether you planned to or not.

Budget for both protocols. Your team needs people who understand FHIR and HL7v2. These are different skill sets. FHIR is REST and JSON. HL7v2 is TCP sockets and pipe-delimited messages from the 1990s. Both are well-documented, but the developer experience is — let's say — not equivalent.

Budget for the middleware. An integration engine isn't optional. You need something between the EHR's HL7v2 feed and your application — Mirth Connect self-hosted, a cloud-managed service like Azure Health Data Services, or a startup like Redox or Health Gorilla that handles the plumbing for you.

Start with FHIR. Even though you'll need HL7v2 for events, FHIR is the right place to start building. (Here's a 30-minute tutorial that gets you from zero to a working SMART on FHIR app.) Your data model, your queries, your test fixtures — build all of that against FHIR. The HL7v2 layer is fundamentally a notification mechanism. The ADT message tells you "something happened." The FHIR API gives you the clinical details.

The Path Forward

The spec-level problem is solved. The R5 Backport IG brings the redesigned Subscription model to R4 servers today. The pieces exist. Vendor adoption is what's missing.

The HTI-2 proposed rule would have forced the issue with certification requirements for FHIR Subscriptions, but it was largely withdrawn in December 2025. Epic is publicly advocating for the R5 Backport IG at the federal level while not yet implementing it themselves. athenahealth is the only major vendor with an actual implementation (20+ subscription topics, still in alpha). Until Epic and Oracle Health ship production support, HL7v2 remains the real-time backbone. Plan accordingly.

Build Today, Evolve Tomorrow

The hybrid pattern isn't going away anytime soon, but it doesn't have to block you.

Build your FHIR queries and data model now. Use a sandbox with realistic synthetic data to develop and test your clinical workflows. When you need real-time events, layer HL7v2 into the architecture. Your FHIR foundation carries forward unchanged when vendors eventually ship Subscriptions.

The practical advice: understand both protocols, budget for the middleware, and build for the hybrid reality. The all-FHIR future is still a few years out.


mock.health gives you a FHIR R4 sandbox with longitudinal patient data you can build against while you sort out your HL7v2 plumbing. Free tier →


Related posts

All posts · Home · Docs