Written and maintained by CASRAI Editorial Board
Last updated
The HL7 FHIR RESTful API specification (http.html) defines the normative HTTP/HTTPS wire protocol through which client applications create, read, update, delete, search, and execute clinical operations on HL7 FHIR resources. Building on standard RFC 9110 HTTP verbs, MIME types (application/fhir+json and application/fhir+xml), and optimistic concurrency headers, the FHIR REST API standardizes how EHRs, health plans, and clinical research platforms exchange granular health data under US Core FHIR and ONC 45 CFR § 170.315(g)(10) mandates.
How Does the HL7 FHIR RESTful API Specification Work?
Every resource on an HL7 FHIR API server is addressed via a canonical URL pattern—https://[base]/[type]/[id]—where [base] is the service root URL, [type] is the case-sensitive FHIR resource name (such as Patient, Observation, or MedicationRequest), and [id] is the logical ID. The specification organizes all RESTful interactions into three hierarchical levels:
- Instance-Level Interactions (Single Resource Record):
read(GET [base]/[type]/[id]): Retrieves the current state of the resource.vread(GET [base]/[type]/[id]/_history/[vid]): Retrieves a specific historical version (meta.versionId) of the resource.update(PUT [base]/[type]/[id]): Replaces the entire resource at the specified ID (or creates it if the server permits client-assigned IDs).patch(PATCH [base]/[type]/[id]): Applies partial updates using JSON Patch (RFC 6902), XML Patch, or a FHIRPath PatchParameterspayload.delete(DELETE [base]/[type]/[id]): Logically removes the resource (preserving version history while returning410 Goneon subsequent reads).history-instance(GET [base]/[type]/[id]/_history): Returns aBundle(type = 'history') of all versions of that resource.
- Type-Level Interactions (Resource Collection):
create(POST [base]/[type]): Creates a new resource with a server-assigned logical ID.search-type(GET [base]/[type]?[parameters]orPOST [base]/[type]/_search): Queries resources of that type using FHIR search parameters and modifiers, returning asearchsetBundle. UsePOST .../_search(withapplication/x-www-form-urlencodedbody) when search parameters contain PHI that must not appear in URL server access logs.- Conditional Interactions: Allows clients to
create(viaIf-None-Existheader),update(PUT [base]/[type]?[search-params]), ordeletebased on search criteria rather than a known logical ID.
- Whole-System Interactions (Server Root):
capabilities(GET [base]/metadata): Fetches the server’sCapabilityStatement.transactionandbatch(POST [base]): Submits aBundleof multiple HTTP operations; atransactionexecutes atomically (all succeed or all roll back), whereas abatchexecutes each entry independently.- Bulk FHIR
$exportand custom extended operations ($[name]).
What HTTP Status Codes and Headers Are Used in FHIR REST API Interactions?
To prevent lost updates when multiple clinicians or apps edit the same patient record simultaneously, the HL7 FHIR RESTful API mandates strict HTTP status codes, weak ETag version tracking, and client preference headers:
| HTTP Status Code or Header | FHIR REST Context | Normative Server & Client Behavior |
|---|---|---|
200 OK / 201 Created / 204 No Content |
Successful read/search/update (200), create (201 with Location header), or delete / minimal return (204) |
On 201 Created, the server MUST return a Location: [base]/[type]/[id]/_history/[vid] header and an ETag |
400 Bad Request vs. 422 Unprocessable Entity |
Malformed JSON/XML syntax or invalid search parameter (400) vs. business rule / profile invariant violation (422) |
Server returns an OperationOutcome resource detailing the exact issue.severity, issue.code, and FHIRPath location |
404 Not Found vs. 410 Gone |
Unknown resource ID (404) vs. previously deleted resource ID (410) |
Allows EHR clients and research registries to distinguish a mistyped ID from an intentionally deleted clinical record |
ETag: W/"[vid]" & If-Match: W/"[vid]" |
Optimistic Concurrency Control (Contention Management) on PUT / PATCH |
Client sends the version ETag it last read in If-Match; if another user updated the resource in the meantime, the server rejects the write with 412 Precondition Failed or 409 Conflict |
If-None-Exist: [search-params] |
Conditional Create on POST [base]/[type] |
Idempotent creation: if 0 matches exist, server creates the resource (201); if 1 match exists, server returns 200 OK without duplicating; if $ge 2$ matches exist, returns 412 Precondition Failed |
Prefer: return=minimal | representation | OperationOutcome |
Response payload control on POST / PUT / PATCH |
Lets bandwidth-constrained clients request an empty body (minimal), the full stored resource (representation), or validation warnings (OperationOutcome) |
Prefer: handling=strict | lenient |
Search parameter validation on GET [base]/[type]?... |
Under strict, the server rejects unknown search parameters with an error; under lenient, it ignores unsupported parameters and lists them in Bundle.link[relation='self'] |
What Is a FHIR CapabilityStatement?
A FHIR CapabilityStatement (retrieved via an unauthenticated or authenticated GET [base]/metadata call) is a machine-readable manifest that declares the exact rules, profiles, and security endpoints supported by a FHIR server:
- FHIR Version and Serialization Formats: Specifies the core version (e.g.,
fhirVersion: "4.0.1") and supported content types (json,xml,ttl). - Security & SMART on FHIR Discovery (
rest.security): Advertises OAuth 2.0 authorization and token URLs alongside the/.well-known/smart-configurationendpoint. - Resource-by-Resource Capabilities (
rest.resource[]): Lists every supported resource type, supported profiles (supportedProfile[]), enabled interactions (read,vread,search-type,create,update), versioning policy (no-version,versioned, orversioned-update), supported search parameters (searchParam[]), and supported_include/_revincludepaths.
Frequently Asked Questions
How does the HL7 FHIR RESTful API specification work?
The HL7 FHIR RESTful API maps clinical resources to URLs ([base]/[type]/[id]) and organizes operations into Instance-level (read, vread, update, patch, delete), Type-level (create, search-type, conditional operations), and Whole-System interactions (capabilities, atomic transaction bundles, and batch bundles) using application/fhir+json or application/fhir+xml payloads.
What HTTP status codes and headers are used in FHIR REST API interactions?
FHIR REST APIs use 200 OK, 201 Created (with a Location header), and 204 No Content for successes; 400 Bad Request, 404 Not Found, 410 Gone, and 422 Unprocessable Entity (with an OperationOutcome body) for errors; and ETag/If-Match (returning 409 or 412 on version collision), If-None-Exist (idempotent conditional create), and Prefer headers to control concurrency and response bodies.
What is a FHIR CapabilityStatement?
A FHIR CapabilityStatement is a normative metadata resource returned by GET [base]/metadata that documents a FHIR server’s supported FHIR version, serialization formats, SMART on FHIR OAuth 2.0 security endpoints, supported resource profiles, allowed CRUD/search interactions, and custom $operations.







