Payerbox Docs

FHIR RESTful API

Payerbox exposes the full base FHIR R4 RESTful API at /fhir — every interaction defined in the FHIR HTTP spec is available without per-resource configuration. This page is a summary of the surface; for full semantic detail, modifier reference, and edge-case behavior, see the Aidbox docs on REST API CRUD and FHIR Search.

The /fhir base uses FHIR-format resources. Aidbox also exposes a non-FHIR / base which uses Aidbox's native resource format — use /fhir for any FHIR-conformant integration.

Endpoints

InteractionMethodURL
CreatePOST/fhir/<type>
Conditional createPOST/fhir/<type>?<search-params> or POST /fhir/<type> + If-None-Exist
ReadGET/fhir/<type>/<id>
vreadGET/fhir/<type>/<id>/_history/<vid>
UpdatePUT/fhir/<type>/<id>
Conditional updatePUT/fhir/<type>?<search-params>
PatchPATCH/fhir/<type>/<id>
DeleteDELETE/fhir/<type>/<id>
Conditional deleteDELETE/fhir/<type>?<search-params>
SearchGET/fhir/<type>?<search-params>
Transaction / batchPOST/fhir/

Auth

SMART Backend Services and Client Credentials. The caller's OAuth client must be allowed (via Aidbox access policies) to perform the interaction on the target resource type. Any interaction may return 403 Forbidden if the client is not authorized. See Authentication.

Create

Endpoint

POST /fhir/<type>

Response codes

StatusCause
201 CreatedResource created; Location, ETag, Last-Modified headers set
400 Bad RequestBody could not be parsed or failed basic FHIR validation
409 ConflictResource with the given id already exists (Aidbox respects id in the body)
422 Unprocessable EntityBody violated profile rules or server business rules

Example

POST /fhir/Patient
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "name": [{"given": ["Bob"], "family": "Smith"}],
  "gender": "male",
  "birthDate": "1970-05-15"
}
HTTP/1.1 201 Created
Location: /fhir/Patient/<id>/_history/1
ETag: W/"1"
Last-Modified: 2026-05-15T13:40:00Z

{
  "resourceType": "Patient",
  "id": "<id>",
  "name": [{"given": ["Bob"], "family": "Smith"}],
  "gender": "male",
  "birthDate": "1970-05-15",
  "meta": {"versionId": "1", "lastUpdated": "2026-05-15T13:40:00Z"}
}

Conditional create

POST /fhir/<type>?<search-params>

Or pass the search criteria in the If-None-Exist header. Outcome depends on the number of matches:

  • No matches — server performs a normal create (201).
  • One match — server returns the existing resource (200), no new resource is created.
  • Multiple matches — 412 Precondition Failed; the criteria were not selective enough.

The same ifNoneExist field is supported inside Bundle.entry.request for transaction bundles (case-sensitive — must be spelled exactly ifNoneExist).

Read

Endpoint

GET /fhir/<type>/<id>

Response codes

StatusCause
200 OKResource returned
404 Not FoundNo resource with the given id
410 GoneResource was deleted

Example

GET /fhir/Patient/<id>
HTTP/1.1 200 OK
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "id": "<id>",
  "name": [{"given": ["Bob"], "family": "Smith"}],
  "gender": "male",
  "birthDate": "1970-05-15",
  "meta": {"versionId": "1", "lastUpdated": "2026-05-15T13:40:00Z"}
}

vread

GET /fhir/<type>/<id>/_history/<vid>

Returns a specific version of the resource. <vid> is the meta.versionId value (typically a monotonically-increasing integer).

Update

Endpoint

PUT /fhir/<type>/<id>

Replaces the resource. If no resource exists at <id>, one is created (upsert semantics). The id cannot be changed once the resource exists.

Response codes

StatusCause
200 OKResource updated
201 CreatedResource did not exist and was created
412 Precondition FailedIf-Match versionId did not match the current version, or If-Match: * was sent and the resource does not exist
422 Unprocessable EntityBody violated profile rules or server business rules

Example

PUT /fhir/Patient/<id>
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "id": "<id>",
  "name": [{"given": ["Bob"], "family": "Smith"}],
  "gender": "male",
  "birthDate": "1970-05-15"
}
HTTP/1.1 200 OK
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "id": "<id>",
  "meta": {"versionId": "2", "lastUpdated": "2026-05-15T13:41:00Z"},
  "name": [{"given": ["Bob"], "family": "Smith"}],
  "gender": "male",
  "birthDate": "1970-05-15"
}

Conditional update

PUT /fhir/<type>?<search-params>

Outcome depends on the number of matches:

  • No matches — server performs a create.
  • One match — server performs the update against the matching resource (the id in the request body is ignored).
  • Multiple matches — 412 Precondition Failed.

Versioned update (optimistic concurrency)

Send If-Match: <versionId> to require that the current meta.versionId matches. On mismatch the server returns 412 Precondition Failed with an OperationOutcome (code: conflict).

Send If-Match: * to update-only (refuse to create if the resource does not exist) — returns 412 instead of creating.

Patch

Endpoint

PATCH /fhir/<type>/<id>

Three patch dialects are supported — pick by Content-Type (or by the _method query parameter):

DialectContent-Type_methodBody shape
Merge Patch (RFC 7386)application/merge-patch+jsonmerge-patchJSON object with the fields to set / null out
JSON Patch (RFC 6902)application/json-patch+jsonjson-patchJSON array of {op, path, value} operations
FHIRPath Patchfhirpath-patchParameters resource with operation parts

If the dialect is not specified, Aidbox infers it: Parameters resourceType → FHIRPath Patch; array body → JSON Patch; otherwise → Merge Patch.

A successful patch fires the same update event as PUT. No-op patches (replacing a field with its current value) return 200 OK but do not fire an event.

Example

PATCH /fhir/Patient/<id>
Content-Type: application/merge-patch+json

{"active": false, "telecom": null}
PATCH /fhir/Patient/<id>
Content-Type: application/json-patch+json

[
  {"op": "replace", "path": "/active", "value": false},
  {"op": "remove",  "path": "/telecom"}
]
PATCH /fhir/Patient/<id>
Content-Type: application/fhir+json

{
  "resourceType": "Parameters",
  "parameter": [{
    "name": "operation",
    "part": [
      {"name": "type",  "valueCode":   "replace"},
      {"name": "path",  "valueString": "Patient.active"},
      {"name": "value", "valueBoolean": false}
    ]
  }]
}

Delete

Endpoint

DELETE /fhir/<type>/<id>

Response codes

StatusCause
200 OKResource deleted (body contains the deleted resource)
204 No ContentResource already deleted, did not exist, or _no-content=true was passed
404 Not FoundResource type not registered
412 Precondition FailedIf-Match versionId did not match the current version

A subsequent GET /fhir/<type>/<id> returns 410 Gone.

Example

DELETE /fhir/Patient/<id>
HTTP/1.1 200 OK
Content-Type: application/fhir+json

{
  "resourceType": "Patient",
  "id": "<id>",
  "meta": {"versionId": "3", "lastUpdated": "2026-05-15T13:42:00Z"},
  ...
}

Conditional delete

DELETE /fhir/<type>?<search-params>
  • No matches — 204 No Content.
  • One match — server performs a normal delete.
  • Multiple matches — 412 Precondition Failed by default. To delete all matches, send x-conditional-delete: remove-all.

Endpoint

GET /fhir/<type>?<param1>=<value1>&<param2>=<value2>&...

Returns a Bundle of type: searchset with the matched resources in entry[].resource, a total count, and link[] entries for pagination (first / prev / self / next / last).

Search parameter types

Each search parameter has a type, declared on the SearchParameter resource, that drives matching semantics:

TypeMatchingExample
stringCase-insensitive, accent-insensitive, starts-with by defaultname=John
tokenExact match on a code or system|code pairstatus=active, identifier=mysystem|123
referenceMatch by reference targetsubject=Patient/123
dateRange comparison with FHIR date prefixes (eq, ne, lt, le, gt, ge, sa, eb)birthdate=ge2019-01-01
numberNumeric comparison; same prefixes as dateprobability=gt0.8
quantityNumeric value comparison only — unit specification not implementedvalue-quantity=75.5
uriExact, case-sensitive URI matchurl=http://example.com
compositeTwo-or-more values joined by $; matches only when both values land on the same elementcode-value-quantity=loinc|12907-2$1
specialImplementation-defined_filter, _text, _content

Modifiers

Append a modifier with a colon to refine the match (<param>:<modifier>=<value>):

ModifierApplies toDescription
:missingallField absent (true) or present (false)
:exactstringExact string match (case- and accent-sensitive)
:contains / :starts / :endsstringSubstring / prefix / suffix
:textallTextual match against the field's text representation
:nottoken, uri, referenceNegate the match
:intokenMatch within a ValueSet
:of-typetokenMatch identifier.type codes
:itokenCase-insensitive
:identifierreferenceMatch Reference.identifier instead of Reference.reference
:iterate / :recurse_include, _revincludeFollow references recursively

Common parameters

ParameterEffect
_idMatch by resource id
_lastUpdatedMatch by meta.lastUpdated (supports date prefixes)
_profileMatch by meta.profile
_elementsReturn only the listed top-level fields (comma-separated, prefix - to exclude)
_countPage size (default page)
_pagePage number (1-based)
_totalnone / estimate / accurate — control the total count strategy
_sortSort key(s); prefix - for descending
_includeInclude resources referenced from the matches
_revincludeInclude resources that reference the matches
_filterBoolean expression for OR across different parameters
_text / _contentFull-text search over narrative / resource body

_include and _revinclude

_include=<source-type>:<search-param>[:<target-type>]
_revinclude=<source-type>:<search-param>[:<target-type>]

Append :iterate to follow the reference chain recursively.

GET /fhir/Patient?_include=Patient:organization
GET /fhir/Organization?_revinclude=Patient:organization
GET /fhir/Observation?_include=Observation:patient&_include:iterate=Patient:link

Chaining

Filter by a property of a referenced resource:

GET /fhir/Patient?general-practitioner:Practitioner.name=Oz
GET /fhir/Practitioner?_has:Patient:general-practitioner:gender=male
  • Forward chain — <reference-param>:<target-type>.<terminal>
  • Reverse chain (_has) — _has:<source-type>:<reference-param>:<terminal>

Chains of any length are supported; mix forward and reverse with . and : joins.

Example

GET /fhir/Patient?name=Smith&gender=male&_count=2&_include=Patient:general-practitioner
HTTP/1.1 200 OK
Content-Type: application/fhir+json

{
  "resourceType": "Bundle",
  "type": "searchset",
  "total": 1,
  "entry": [
    {
      "resource": {
        "resourceType": "Patient",
        "id": "<id>",
        "name": [{"family": "Smith", "given": ["John"]}],
        "gender": "male"
      },
      "search": {"mode": "match"}
    }
  ],
  "link": [
    {"relation": "self", "url": "/fhir/Patient?name=Smith&gender=male&_count=2&_page=1"}
  ]
}

Transaction and batch

POST /fhir/

Submit a Bundle of type: transaction (all-or-nothing) or type: batch (per-entry, independent failures). Each entry.request carries an HTTP method and URL — the server applies the entries and returns a Bundle of type: transaction-response / batch-response with the per-entry outcomes and resolved references.

Validate

Dry-run validation against the FHIR core schema and any profile the resource claims via meta.profile. Always returns 200 OK; the outcome is in OperationOutcome.id — allok or validationfail.

POST /fhir/<resourceType>/$validate
POST /fhir/<resourceType>/<id>/$validate

The same validator runs on every Create / Update / Patch — when the resource carries a meta.profile from one of the loaded Implementation Guides, a failed write returns 422. See $validate in the Aidbox docs for modes, profile parameter, and async validation.

Errors

StatusCause
400Body parse failure or malformed search expression
401Missing or invalid token
403OAuth client not authorized to perform the interaction on this resource type
404Resource type unknown, or instance not found
409id already exists (create only)
410Resource was deleted
412Conditional precondition failed — If-Match mismatch, conditional create / update / delete with multiple matches
422FHIR-profile or business-rule validation failure
500Server-side error

All 4xx and 5xx responses carry an OperationOutcome body describing the failure.

For full semantic detail — additional modifiers, advanced _filter operators, custom SearchParameter registration, AidboxQuery / Search resource / dot-expressions as alternatives to FHIR Search — see the Aidbox REST API docs. For Payerbox-specific operations layered on top of this base API, see the Operations index.

Last updated: