FHIR R4 vs vendor APIs for revenue cycle data
You connect to an ambulatory EHR through its FHIR R4 endpoint. You read Patient and Coverage on the first afternoon. Then you search for the claim the practice sent last week and the server returns an empty Bundle. The claim exists. The FHIR endpoint does not expose it.
What the certified endpoint must serve
US EHR vendors certify their API to the ONC criterion 170.315(g)(10). The criterion names FHIR Release 4.0.1, the US Core implementation guide at STU 6.1.0, SMART App Launch 2.0.0 and Bulk Data Access 1.0.0. Newer US Core versions are approved through the standards version advancement process.
US Core defines the profiles the endpoint must support. The US Core 6.1.0 profile list includes Patient, Coverage, Encounter, Condition, Procedure, Organization, Practitioner and PractitionerRole. It does not include Claim or ExplanationOfBenefit.
The profiles that matter for billing carry these must-support fields:
- US Core Patient: identifier, name, telecom, gender, birthDate, address and communication language. There is no guarantor, account or insurance element.
- US Core Coverage: a member ID or subscriberId, status, type, beneficiary, relationship, period, payor, and class slices for group and plan. The profile notes that status alone does not show whether the patient is covered. Read period too.
- US Core Encounter: identifier, status, class, type, subject, participant, period, reasonCode, discharge disposition, location and serviceProvider. Encounter.account exists in the base resource and is not must-support.
Claim and ExplanationOfBenefit in FHIR R4
Both resources exist in the base specification. Claim is a request resource with a use of claim, preauthorization or predetermination. ExplanationOfBenefit combines a Claim, a ClaimResponse and optional Account data into one record scoped to one payer's adjudication. Both sit at maturity level 2, Trial Use.
The profiles that constrain ExplanationOfBenefit come from the payer side. The CARIN Blue Button implementation guide describes resources that payers display to consumers through a FHIR API. Its C4BB ExplanationOfBenefit Professional NonClinician profile models professional claims after the CMS-1500 form and requires an adjudication amount on each item and on the claim total. A payer serves this data to a member's app. An EHR does not serve it to a billing vendor.
So the FHIR endpoint gives you the patient, the coverage on file and the visit. It does not give you the claim the practice management system built, the charges on it, the 837 it sent, the 277CA that came back or the 835 that paid it.
FHIR also defines CoverageEligibilityRequest for the provider-to-insurer eligibility question. US Core does not profile it, so a certified endpoint has no obligation to support it.
What the vendor API adds
A vendor FHIR server can serve more than US Core, and the extra surface is contract gated. The eClinicalWorks FHIR documentation lists Coverage under read, and lists create, update and delete on Coverage as operations that require a contract. The same documentation sets a limit of 500 calls per minute per base URL, returns HTTP 429 above it, and accepts only RS384 for asymmetric client authentication. It does not list Claim or ExplanationOfBenefit, so the public documentation does not state whether either resource is available.
Beyond FHIR, each vendor keeps internal interfaces for its billing module. These carry the charge, the CPT and modifiers per line, the diagnosis pointers, the claim status the practice sees on screen, the payment posted against the line and the patient balance. Access, authentication and schema differ per vendor. Where a vendor publishes no documentation for this layer, the shape comes from a partner agreement and from reading the data.
The open source Python and TypeScript eClinicalWorks connectors cover the FHIR layer: SMART Backend Services authentication, get, search, create and update.
Where the two layers disagree
When you read both, the same patient looks different in each.
| Data | FHIR R4 with US Core | Billing module |
|---|---|---|
| Insurance | Coverage with member ID, group and plan. Period can be open ended. | Insurance record with payer rank, the last eligibility result and the copay from it. |
| Visit | Encounter with class, period and serviceProvider. | Appointment with visit type, charge slip and a link to the claim. |
| Claim | Not served. | Claim with lines, status and payer claim control number. |
| Payment | Not served. | Posted payment, adjustment and patient balance. |
Coverage carries no payer rank. The billing module does. Map the Coverage to the billing insurance record by member ID and payor, and take the rank from the billing side.
Why teams use both
The FHIR layer is stable. ONC certifies it, HL7 versions it, and the documentation is public. Build patient matching, demographics sync and coverage discovery on it. Use Bulk Data group export for the initial load.
The vendor layer is where revenue cycle work happens. Claims, remits, patient balances and payment posting live there. Build those features on it, and isolate it behind one internal schema, because its shape changes with each vendor release.
A workable model keeps one record per patient keyed on the FHIR Patient id, with the billing module's account number as a second identifier. One record per visit keyed on the Encounter id and the billing module's visit id. Claims and payments keyed on billing module identifiers alone, with a link back to the Encounter. TheFhirStorm exposes patient, encounter, claim, eligibility, claim status and remit data through one schema of this shape across practice management systems, EHRs and payer portals.