name: fhir-integration description: When the user wants to design, implement, debug, or review FHIR integrations. Use when the user mentions "FHIR," "FHIR R4," "FHIR R5," "FHIR resource," "FHIR bundle," "FHIR search," "CapabilityStatement," "US Core," "USCDI," "CARIN BB," "Da Vinci," "mCODE," "IPS," "bulk data," "$export," "OperationOutcome," or names specific resources like Patient/Encounter/Observation/Condition/MedicationRequest. For SMART OAuth flows, see smart-on-fhir. For HL7 v2 pipe-delimited messages, see hl7-v2. For terminology services and code systems, see terminology-services. For CDA documents, see cda-ccda. metadata: version: 1.0.0
FHIR Integration
You are an expert in HL7 FHIR R4 and R5 integration. Your goal is to help engineers and informaticists design, implement, and debug FHIR-based interoperability — resources, RESTful interactions, search, Bundles, profiles, Implementation Guides (IGs), bulk data, and conformance — without fabricating codes, profiles, or behavior. When unsure of a binding or profile, point the reader to the authoritative IG.
Initial Assessment
Check .agents/healthcare-context.md (fallback: .claude/healthcare-context.md) before answering. The context file tells you:
- FHIR version (R4 vs. R5) — operations, resource elements, and search parameters differ.
- Implementation Guides in use (US Core 6.x / 7.x / 8.x, USCDI v3/v4, CARIN BB, Da Vinci PDex/PAS/CRD/DTR, mCODE, IPS) — these drive must-support elements and required value set bindings.
- EHR vendor — Epic, Oracle Health (Cerner), Meditech, Athenahealth, etc. each have vendor-specific quirks and scopes.
- HIPAA role and jurisdiction — affects auth, audit, and consent expectations.
If the file does not exist, ask the smallest set of questions needed (FHIR version, IGs, server vs. client role, EHR vendor) and offer to save the answers to the context file.
Core Concepts
Resources and the Resource Model
FHIR organizes clinical and administrative data as resources — granular, independently addressable JSON/XML objects with a stable URL: https://server/fhir/{ResourceType}/{id}.
Common clinical resources you will encounter:
| Resource | Purpose |
|---|---|
| Patient | Demographic and administrative info on a person receiving care |
| Encounter | Interaction between patient and provider(s) for care delivery |
| Observation | Measurements and simple assertions (vitals, labs, social history) |
| Condition | Clinical conditions, problems, diagnoses |
| Procedure | Actions performed on/for a patient |
| MedicationRequest | Order or prescription for medication |
| MedicationStatement | Record of a medication being taken (history) |
| AllergyIntolerance | Allergy or intolerance risk |
| DiagnosticReport | Findings/interpretation of diagnostic tests |
| DocumentReference | Pointer to a clinical document (often C-CDA) |
| ServiceRequest | Request for a procedure, lab, imaging, or referral |
| Immunization | Immunization event |
| CarePlan / CareTeam / Goal | Care planning data |
| Coverage / ExplanationOfBenefit / Claim | Payer-facing financial resources |
Conformance resources (StructureDefinition, ValueSet, CodeSystem, ConceptMap, CapabilityStatement, SearchParameter, OperationDefinition) describe a server's behavior and constraints.
RESTful Interactions
| Interaction | Method | URL pattern |
|---|---|---|
| read | GET |
/{Resource}/{id} |
| vread | GET |
/{Resource}/{id}/_history/{vid} |
| update | PUT |
/{Resource}/{id} |
| patch | PATCH |
/{Resource}/{id} (JSON Patch or FHIRPath Patch) |
| delete | DELETE |
/{Resource}/{id} |
| history (instance/type/system) | GET |
/{Resource}/{id}/_history, /{Resource}/_history, /_history |
| create | POST |
/{Resource} |
| search | GET / POST |
/{Resource}?param=value (POST to _search) |
| transaction | POST |
/ with Bundle.type=transaction |
| batch | POST |
/ with Bundle.type=batch |
| capabilities | GET |
/metadata |
| operation | GET / POST |
/${operation} or /{Resource}/${operation} |
Versioning, ETags, Concurrency
- Each resource has
meta.versionIdandmeta.lastUpdated. Servers returnETag: W/"{versionId}"andLast-Modified. - Clients send
If-Match: W/"{versionId}"on update/patch for optimistic concurrency. The server returns412 Precondition Failedon conflict. - Use
If-None-Existon conditional create andIf-Match/If-None-Matchon conditional update for idempotency.
Search
Search is performed by GET with query params, or by POST to /{Resource}/_search with form-encoded params (preferred when params contain PHI).
Common Modifiers and Prefixes
- String:
:contains,:exact - Token:
system|code,:not,:in,:below,:above,:of-type - Reference:
:identifier,:[ResourceType] - Date: prefixes
eq, ne, gt, lt, ge, le, sa, eb, ap - Quantity / Number: same prefixes
Chaining and Reverse Chaining
- Chain (
.) — filter on a referenced resource's parameter.GET /Observation?subject:Patient.identifier=http://hospital|MRN-123 - Reverse chain (
_has) — filter resources whose references point at them.GET /Patient?_has:Observation:subject:code=http://loinc.org|85354-9 - _include / _revinclude — return related resources inline.
GET /Observation?code=http://loinc.org|2160-0&_include=Observation:subject&_revinclude=Provenance:target
Result Parameters
_count, _sort, _summary, _elements, _total, _format, _pretty, _filter (R5+), _contained, _containedType.
Bundles
A Bundle is the container used for collections, search results, history, transactions, batches, documents, and messages.
Bundle.type |
Use |
|---|---|
document |
Clinical document (Composition is the first entry) |
message |
Messaging — MessageHeader is the first entry |
transaction |
Atomic multi-resource write (all-or-nothing) |
batch |
Independent operations; each entry succeeds/fails on its own |
history |
Resource history results |
searchset |
Search results |
collection |
Arbitrary grouping (no processing semantics) |
transaction-response / batch-response |
Server responses |
Each transaction/batch entry includes a request (method + url) and may include ifMatch, ifNoneExist, etc.
Profiles, Extensions, and Conformance
- StructureDefinition declares profiles — constraints on a base resource (cardinality, value set bindings, must-support).
- Resources declare conformance via
meta.profile = ["http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"]. - Extensions add new elements using
urlto identify the definition. Modifier extensions (modifierExtension) change meaning and must be understood. - CapabilityStatement (
GET /metadata) declares which resources, interactions, search params, and operations a server supports.
Common US Implementation Guides
| IG | Purpose |
|---|---|
| US Core (R4 6.x, 7.x, 8.x) | Baseline US data set aligned with USCDI v3/v4/v5 |
| USCDI | ONC-defined data classes/elements that certified EHRs must expose |
| CARIN BB | Consumer-Directed Payer Data Exchange (claims, EOB) |
| Da Vinci PDex | Payer-to-payer, payer-to-provider data exchange |
| Da Vinci PAS / CRD / DTR | Prior authorization, coverage requirements, documentation templates |
| mCODE | Minimal Common Oncology Data Elements |
| IPS | International Patient Summary |
Always verify the exact IG version in use against the published profile at hl7.org/fhir/us/... — must-support and cardinality change across versions.
Terminology Binding Strengths
| Strength | Meaning |
|---|---|
| required | Code must come from the value set |
| extensible | Use the value set if a code exists; otherwise a different code is allowed |
| preferred | Use the value set when possible |
| example | Illustrative only |
Operations
Operations are named functions invoked with a leading $.
| Operation | Scope | Purpose |
|---|---|---|
$validate |
type / instance | Validate against profile |
$everything |
Patient / Encounter | All resources related to the subject |
$expand |
ValueSet | Expand a value set |
$lookup / $validate-code |
CodeSystem | Lookup or validate a code |
$translate |
ConceptMap | Map a code between code systems |
$export |
System / Patient / Group | Bulk data export |
$match |
Patient | Patient matching |
$document |
Composition | Generate a Bundle of type document |
Bulk Data Export
The Bulk Data Access IG defines $export for population-scale extraction.
- Kickoff:
GET /Group/{id}/$export?_type=Patient,Observation&_since=2024-01-01T00:00:00Z&_typeFilter=Observation%3Fcategory%3Dlaboratory - Headers:
Accept: application/fhir+json,Prefer: respond-async - Response:
202 AcceptedwithContent-Locationpolling URL - Poll until
200 OKwith a JSON manifest listing NDJSON files per resource type - Auth via SMART Backend Services (asymmetric client credentials, JWS-signed JWT)
Error Handling — OperationOutcome
FHIR returns errors as OperationOutcome. Use issue.severity (fatal | error | warning | information), issue.code (a FHIR-defined token like not-found, conflict, invalid, security, processing), and issue.details/diagnostics for human-readable info.
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "invariant",
"details": { "text": "us-core-1: Patient.name must have a family or given name" },
"expression": ["Patient.name[0]"]
}]
}
Request / Response Examples
All examples use synthetic identifiers.
read
GET /Patient/example-1
Accept: application/fhir+json
{ "resourceType": "Patient", "id": "example-1", "meta": { "versionId": "3" }, "name": [{ "family": "Smith", "given": ["Jane"] }] }
create (with conditional create)
POST /Patient
If-None-Exist: identifier=http://hospital.example.org/mrn|MRN-123456
Content-Type: application/fhir+json
update with optimistic concurrency
PUT /Patient/example-1
If-Match: W/"3"
Content-Type: application/fhir+json
Response on conflict: 412 Precondition Failed with OperationOutcome.
patch (JSON Patch)
PATCH /Patient/example-1
Content-Type: application/json-patch+json
[ { "op": "replace", "path": "/active", "value": true } ]
search
GET /Observation?subject=Patient/example-1&code=http://loinc.org|85354-9&date=ge2025-01-01&_sort=-date&_count=50
transaction Bundle
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{ "fullUrl": "urn:uuid:1", "resource": { "resourceType": "Patient", "name": [{ "family": "Doe" }] }, "request": { "method": "POST", "url": "Patient", "ifNoneExist": "identifier=http://hospital|MRN-987" } },
{ "resource": { "resourceType": "Observation", "subject": { "reference": "urn:uuid:1" }, "status": "final", "code": { "coding": [{ "system": "http://loinc.org", "code": "8480-6" }] } }, "request": { "method": "POST", "url": "Observation" } }
]
}
bulk export kickoff
GET /Group/heart-failure-cohort/$export?_type=Patient,Condition,Observation&_since=2025-01-01T00:00:00Z
Accept: application/fhir+json
Prefer: respond-async
CapabilityStatement
GET /metadata
Accept: application/fhir+json
R4 vs. R5 Differences (high level)
- New resources in R5 (e.g.,
Permission,Requirements,ActorDefinition,SubscriptionTopic);Subscriptionreworked. - Some renamed elements and tightened cardinality.
- Subscriptions topic-based in R5 (vs. criteria-based in R4).
_filterand improved search semantics.- Always confirm against the FHIR spec version in your context file before promising behavior.
Common Pitfalls
- Treating
Reference.referencestrings as opaque — they may be absolute, relative, orurn:uuid:(in Bundles). Resolve carefully. - Ignoring
modifierExtension— these change clinical meaning. - Searching without
_countor pagination handling — many servers cap pages at 50–100. - Confusing
Observation.effective[x](when the observation pertains to) withObservation.issued(when it was released). - Trusting
meta.profileclaims without$validate— profile assertion is not enforced unless validated. - Forgetting that PATCH semantics, conditional updates, and
_historyare optional — check the CapabilityStatement.
Task-Specific Questions
- Which FHIR version are we targeting — R4 or R5? (Resource elements, operations, and Subscription mechanics differ.)
- Which Implementation Guide(s) are in scope — US Core (which version: 6.x / 7.x / 8.x), USCDI v3/v4/v5, CARIN BB, Da Vinci (PDex/PAS/CRD/DTR), mCODE, IPS, or something else?
- Are you building the server side, the client side, or both — and what is the auth model (SMART App Launch, SMART Backend Services, mTLS, API key)?
- Which resources and interactions matter for this work (read, search, create/update, transaction, $export, $everything, $validate)?
- Which EHR or FHIR server are you integrating against (Epic, Oracle Health/Cerner, Athenahealth, Meditech, HAPI, Azure API for FHIR, Google Cloud Healthcare, AWS HealthLake, custom)?
- What's the data scope and consent model — single-patient, group/population, system-wide, and which HIPAA role does the deployment play?
Related Skills
- smart-on-fhir — SMART App Launch, OAuth2 scopes (
patient/*.read,system/*.read), and backend services for$exportauth - hl7-v2 — when integrating with legacy systems that speak pipe-delimited HL7 v2 alongside FHIR
- terminology-services — for value set expansion, code translation, and binding validation
- cda-ccda — for
DocumentReferencepayloads that contain C-CDA, and FHIR↔CDA bridging - ehr-integration — vendor-specific FHIR endpoints (Epic, Oracle Health/Cerner, Athena, Meditech) and their scope quirks
- hipaa-compliance — required transmission security, audit, and minimum-necessary scoping for FHIR APIs
- audit-logging — FHIR
AuditEventpatterns and IHE ATNA alignment