Skip to content
DWKD

Tool note

Epic: FHIR Version Fragmentation, per Operation

The same resource can support read at one FHIR version and create at another, so plan per operation rather than per resource.

“Does Epic support Condition?” is a question with no useful answer. The resource is published; that tells you almost nothing about whether the thing you need to do with it is available to you.

The unit of support is not the resource. It is the resource, the operation and the FHIR version together, and sometimes a specifically named API variant on top of that.

Why this exists

The failure mode is quiet and expensive. You check a support index, see your resource listed, choose a version for the app, and estimate from that. In week three the create you need turns out not to exist at the version your reads use, and now you are choosing between a mapping layer, a second version in the client, and telling the client a feature is cut.

Two worked examples from Epic’s own published index show the shape. Condition (Problems) has Read, Search and Create on R4, Create on STU3, and Read and Search on DSTU2, plus a CDS Hooks variant on R4. Immunization is stranger: base Read and Search are STU3 and DSTU2, while R4 arrives as separately named Immunization.Read (Patient Chart) and Immunization.Search (Patient Chart) APIs.

Here is the consequence people miss. Two versions of one concept are two data shapes. A DSTU2 Condition and an R4 Condition are not the same JSON, so an app that reads one and writes the other owns a mapping, and a test for that mapping, for as long as the feature lives. That cost belongs in the estimate rather than in week three.

How to use it

Build the matrix before the estimate goes out. One row per operation you actually need, with the published API name copied exactly, the versions it exists at, the scope, whether it matches your app’s primary version, and a decision.

  • Every row gets exactly one decision: build, map, add version, cut, or investigate. A row with no decision is an assumption, and assumptions are what the matrix is for.
  • Price investigate rows as time-boxed investigation instead of folding them into the build number. That is the honest way to charge for not knowing yet.
  • Write the date you checked the index on the sheet. A matrix with no date is a rumor, because published support moves.
  • Where an operation is published under a specific name, copy the name character for character. Registration and scopes attach to the published name, not to the resource concept, and a near-miss name fails at the token rather than at the parser — which is a much less obvious error to read.
  • Treat base URL, client identifier and organization identifier as configuration held in one place. They do change: a sandbox notice dated August 31, 2026 reverted the sandbox organization identifier to 0 from 529 and told integrators who had switched to revert their identifiers.
  • Put the cut rows in the scope document, so the cut is visible to the client rather than quietly absorbed by you.

Where it goes wrong

The matrix is a planning tool, not a compatibility guarantee. A published index tells you what exists in general. A specific site’s configuration, licensing and version decide what you actually get, so confirm per site and write that confirmation date next to the row.

Do not copy version answers out of anybody’s worksheet, including this one, into a live plan. Look it up yourself the week you commit to it.

If your app reads one resource one way, the matrix is a single row and the ceremony is waste. Scale the artifact to the surface you are touching.

And be suspicious of your own willingness to add a version. Supporting two means every change ships twice, is tested twice, and breaks in two ways. Cutting the feature is sometimes the better engineering decision, and part of what the matrix is for is making that trade visible early enough that you can still take it.

Copy and Clear become available when the worksheet is ready.

FHIR OPERATION x VERSION MATRIX

App: Site:

Checked against the published support index on:

Primary version chosen for this app:

A matrix with no checked-on date is a rumor. Re-check before go-live.

ONE ROW PER OPERATION YOU ACTUALLY NEED

resource | operation | published API name (exact) | version(s) | scope | matches primary? | decision


Condition (Problems) | Read | | R4, DSTU2 | <> | <> | <>

Condition (Problems) | Search | | R4, DSTU2 | <> | <> | <>

Condition (Problems) | Create | | R4, STU3 | <> | <> | <>

Immunization | Read | Immunization.Read (Patient Chart) | R4 | <> | <> | <>

Immunization | Read | base resource as published | STU3, DSTU2| <> | <> | <>

| | <> | <> | <> | <> | <>

The rows above show the shape of the problem - the same concept carrying

different operations at different versions, and an R4 operation published under

its own name. They are not a substitute for looking your own operations up in

the index on the day you estimate.

DECISION VALUES - every row gets exactly one

build exists at my primary version; nothing special to do

map I must call another version; I own the shape mapping and its test

add version I will support a second version in the client

cut the feature does not ship, and the client is told in writing

investigate I do not know yet; priced as investigation, not as build

FOR EVERY "map" ROW, ANSWER

FOR EVERY "add version" ROW, ANSWER

NAMED API VARIANTS

Some operations are published as separately named APIs rather than as the plain

resource. Registration and scopes attach to the name.

CONFIGURATION THAT WILL MOVE UNDER YOU

dated August 31, 2026 reverted the sandbox organization identifier to 0

from 529 and asked integrators who had switched to revert their OID

system identifiers.

BEFORE THE ESTIMATE GOES OUT