FHIR Search
When working with the Oystehr FHIR API you will regularly need to search for resources matching a search query. Search allows you to join, filter, sort, and so much more (opens in a new tab).
To get you started with FHIR search, we'll go over the most common search parameters and how to use them.
Search Basics
To perform a search query, you need a resource type and a search parameter. For example, to search for all patients with the name "Jon", you would would look up the appropriate search parameter in the Patient resource documentation (opens in a new tab). In this case, the search parameter is given.
You can then use the search parameter in a search query with either the API or SDK:
Search for all patients named "Jon" with the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'given',
value: 'Jon',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();Successful search queries will return a Bundle (opens in a new tab) resource containing the matching resources. The Bundle resource is used to convey an array of FHIR resources. As an example, the above query might return the following response:
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"fullUrl": "https://fhir-api.zapehr.com/Patient/6bbdbadf-4f60-4bdd-8c54-b37970c584b2",
"resource": {
"resourceType": "Patient",
"active": true,
"name": [
{
"given": ["Jon"],
"family": "Snow"
}
],
"id": "6bbdbadf-4f60-4bdd-8c54-b37970c584b2",
"meta": {
"versionId": "ef4e3e20-4103-4df5-8f89-b4f49d6310b3",
"lastUpdated": "2023-11-15T18:11:31.740Z"
}
},
"search": {
"mode": "match"
}
}
],
"link": [
{
"relation": "self",
"url": "https://testing.fhir-api.zapehr.com/Patient?_count=20&_elements=&given=Jon"
},
{
"relation": "first",
"url": "https://testing.fhir-api.zapehr.com/Patient?_count=20&_elements=&_offset=0&given=Jon"
}
]
}Any resources matching the search criteria will be included in the entry array. In this case, there is only one patient named "Jon" in the system, so only one resource is returned.
The link array contains relations like first, prev, next, and last which you can use to fetch other pages when there was more matching data than was returned in the query. In this case we only have one page of results, so only self and first are returned.
You can search for resources using a GET request, as in the examples above, or using a POST request. For POST requests, the URL must contain /:resource/_search, as opposed to /:resource, which is used for GET requests. The following example highlights this difference:
Example
Search for all patients named "Jon" with a GET request:
curl --location 'https://fhir-api.zapehr.com/r4/Patient?given=Jon' \
--header 'Authorization: Bearer <your_access_token>' \
--header 'x-oystehr-project-id: <your_project_id>'Searches With Long Parameters
The Oystehr FHIR API has a limit of 10KB for the length of a URL. Should you exceed this limit, your request will fail with HTTP Status Code 414. If you need to perform a search with a long parameter, or with many parameters, you can use a POST request to avoid the URL length limit. See the example above for cURL syntax.
The Oystehr TypeScript SDK uses POST requests for all search queries, so you don't need to worry about URL length limits when using the SDK.
Total Count
When performing a FHIR search, the resulting Bundle includes a total attribute. This represents the total number of matches for the search, regardless of page size. By default this total is an estimate. You may want an exact count to facilitate exhaustive listing, or not to bother with a count at all. You can control this behavior by including the _total parameter in your search parameters:
none— Do not include atotalattribute on the responseBundleestimate— Include an estimatedtotalon the responseBundle; this is the default behavioraccurate— Include an exacttotalfor the search; searches using this parameter will see a performance penalty
For more information about this search parameter, see the FHIR Search documentation (opens in a new tab).
Search Modifiers
Search modifiers are used to modify the behavior of a search parameter. For example, you can use the not modifier to search for a resource that does not have a certain value for a field. Modifiers are appended to the end of a search parameter with a colon. For example, to search for all patients that are not active, you would use the not modifier on the active search parameter:
Search for all patients that are not active using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'active:not',
value: 'true',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();Here are some of the most frequently used modifiers:
:not— Search for resources that do not have a certain value for a "token" property. Token (opens in a new tab) search parameters are used when searching for an exact match for a code or identifier.:exact— Search for resources that have an exact match for a "string" property.:contains— Search for resources that contain a certain value for a "string" or "uri" property.:missing— Search for resources that do not have a certain property.
The full list of modifiers can be found in the FHIR Search documentation (opens in a new tab).
Sorting
You can sort the results of a search query by using the _sort parameter. For example, to sort patients alphabetically by their given name, you would use the given search parameter with the _sort parameter:
Search for all patients sorted by given name using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: '_sort',
value: 'given',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();Sort the opposite direction by adding a - before the parameter name like, _sort=-given.
You can sort by multiple parameters by separating them with a comma, _sort=given,family.
Limiting Page Size
Individual FHIR resources can be quite large, so to keep searches running quickly, you may want to limit the number of resources returned in one page. You can do this with the _count parameter:
Search for all patients returning only ten in each page using the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: '_count',
value: '10',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();You can get the next page of results by using the link relation next, as described in the Pagination section.
Pagination
When a search query returns more results than can fit in a single page, the results are paginated. The Bundle resource returned by the search query will include a link array with relations like first, prev, next, and last. You can use these links to navigate through the pages of results.
For example, if you wanted to grab all resources matching a search query across all pages, you could use the next link to fetch each page of results until there are no more pages. Here's a typescript example which uses the Oystehr SDK to do that:
import { Appointment } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
let results: Patient[] = [];
let offset = 0;
let params = [
{
name: '_count',
value: '100',
},
{
name: '_offset',
value: offset,
},
];
let resources = await oystehr.fhir.search({
'Patient',
params,
});
results = results.concat(resources.unbundle());
while ((resources.link as BundleLink[] | undefined)?.find((link) => link.relation === 'next')) {
resources = await oystehr.fhir.search({
'Patient',
params: params.map((param) => {
if (param.name === '_offset') {
return {
...param,
value: (offset += 100),
};
}
return param;
}),
});
results = results.concat(resources.unbundle());
}
console.log(`Found ${results.length} patients across all pages.`);These links are also useful for implementing typical pagination features in your application, such as "Load More" buttons or infinite scrolling.
Joining Referenced Resources
The _include and _revinclude parameters enable returning referenced resources in search results. You can think of this like a JOIN in SQL.
For example, if you were building an appointments feature in an EHR, you might want to query up appointments to show a calendar of upcoming appointments. For every appointment you query with your search, you also want the information about the patient the appointment is for. You can do this with the _include parameter:
Search for appointments joining in their referenced patients with the v3 SDK:
import { Appointment } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<Appointment | Patient>*/ = await oystehr.fhir.search<Appointment | Patient>({
resourceType: 'Appointment',
params: [
{
name: '_include',
value: 'Appointment:patient',
},
],
});The above query will return a Bundle containing all appointments, and for each appointment, the patient resource will be included in the entry array. The patient resource will be included in the entry array, and its search.mode will be include:
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"fullUrl": "https://fhir-api.zapehr.com/Appointment/2abde332-dd3e-4e3f-a317-4652cf32d991",
"resource": {
"resourceType": "Appointment",
"status": "booked",
"start": "2023-12-10T09:00:00Z",
"end": "2023-12-10T10:00:00Z",
"participant": [
{
"actor": {
"reference": "Patient/542754df-9215-4b54-ac6e-870eaffed1af"
},
"required": "required",
"status": "accepted"
}
],
"id": "2abde332-dd3e-4e3f-a317-4652cf32d991",
"meta": {
"versionId": "1ca1ef9a-acd1-499a-8ebe-ed60e5b7ca4f",
"lastUpdated": "2023-11-16T04:02:06.227Z"
}
},
"search": {
"mode": "match"
}
},
{
"fullUrl": "https://fhir-api.zapehr.com/Patient/542754df-9215-4b54-ac6e-870eaffed1af",
"resource": {
"resourceType": "Patient",
"active": true,
"name": [
{
"given": [
"Jon"
],
"family": "Snow"
}
],
"address": [
{
"use": "home",
"type": "physical",
"text": "Winterfell"
}
],
"id": "542754df-9215-4b54-ac6e-870eaffed1af",
"meta": {
"versionId": "c2047012-a48c-44e8-a77b-cdb3c2ba7fea",
"lastUpdated": "2023-11-16T03:24:31.230Z"
}
},
"search": {
"mode": "include"
}
}
],
...
}_revinclude is just like _include, except it returns resources that reference the resource you are searching for. If, when searching for Patients, you wanted to also return Appointments that reference those patients, you could use _revinclude. You could get basically the same result as above by searching for patients and "_revincluding" their appointments:
Search for patients joining in appointments which reference them with the v3 SDK:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<Appointment | Patient>*/ = await oystehr.fhir.search<Appointment | Patient>({
resourceType: 'Patient',
params: [
{
name: '_revinclude',
value: 'Appointment:patient',
},
],
});Nested Referencing
If you need to move the _include and _revinclude functionality one step further you can use _include:iterate and _revinclude:iterate to join references of the referenced resources up to 5 layers in depth.
For example, if you need to get not only an appointment with related patient, but also the general practitioner of this patient, their practitioner role, organization that this role belongs to, and in addition to all that the organization that the first organization is part of, you can make a chain of _include:iterate/_revinclude:iterate parameters to get this structure.
Of course, it doesn't have to be this complicated, and you can use fewer layers. But this is an example of the highest level of complexity that you can achieve. If we shorten it to something a bit more reasonable, like only adding the patient, their general practitioner and their role, such a request would look like this:
Search for appointments, joining in patients, practitioners, and practitioner roles, with the SDK:
import { Appointment } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<Appointment | Patient | Practitioner | PractitionerRole>*/ = await oystehr.fhir.search<Appointment | Patient | Practitioner | PractitionerRole>({
resourceType: 'Appointment',
params: [
{
name: '_include:iterate',
value: 'Appointment:patient',
},
{
name: '_include:iterate',
value: 'Patient:general-practitioner',
},
{
name: '_revinclude:iterate',
value: 'PractitionerRole:practitioner',
},
],
});This query will return a similarly structured bundle as for regular _include/_revinclude parameter but with more resource types included:
{
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"fullUrl": "https://fhir-api.zapehr.com/Appointment/6ca312c0-2bc9-4f69-acee-0ffd44cf9a84",
"resource": {
"resourceType": "Appointment",
"status": "booked",
"appointmentType": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v2-0276",
"code": "FOLLOWUP",
"display": "A follow up visit from a previous appointment"
}
]
},
"start": "2025-12-04T09:30:00.000+02:00",
"end": "2025-12-04T10:00:00.000+02:00",
"minutesDuration": 30,
"participant": [
{
"actor": {
"type": "Patient",
"reference": "Patient/d5dd9861-1fc4-46d5-9c69-c4e393f2c1e4"
},
"required": "required",
"status": "accepted"
}
],
"id": "6ca312c0-2bc9-4f69-acee-0ffd44cf9a84",
"meta": {
"versionId": "13e17cd7-4fb2-4cca-b5c7-260f845a0ef8",
"lastUpdated": "2025-12-03T12:41:52.608Z"
}
},
"search": {
"mode": "match"
}
},
{
"fullUrl": "https://fhir-api.zapehr.com/Patient/d5dd9861-1fc4-46d5-9c69-c4e393f2c1e4",
"resource": {
"id": "d5dd9861-1fc4-46d5-9c69-c4e393f2c1e4",
"meta": {
"versionId": "e60e403b-66c0-4c8c-8b41-6ae577a1db7d",
"lastUpdated": "2025-12-03T12:47:24.323Z"
},
"name": [
{
"given": [
"Jon"
],
"family": "Snow"
}
],
"active": true,
"address": [
{
"use": "home",
"text": "Winterfell",
"type": "physical"
}
],
"resourceType": "Patient",
"generalPractitioner": [
{
"type": "Practitioner",
"reference": "Practitioner/714c7b76-38b7-4618-929b-42d4c1c5d01b"
}
]
},
"search": {
"mode": "include"
}
},
{
"fullUrl": "https://fhir-api.zapehr.com/Practitioner/714c7b76-38b7-4618-929b-42d4c1c5d01b",
"resource": {
"id": "714c7b76-38b7-4618-929b-42d4c1c5d01b",
"meta": {
"versionId": "16ba42b8-7a42-4bbb-912a-9737e0451bf0",
"lastUpdated": "2025-12-03T12:45:10.368Z"
},
"name": [
{
"given": [
"Aemon"
],
"family": "Targaryen"
}
],
"gender": "male",
"resourceType": "Practitioner"
},
"search": {
"mode": "include"
}
},
{
"fullUrl": "https://fhir-api.zapehr.com/PractitionerRole/bd9cbf9d-a72b-4fd3-b302-b5e5e1925c16",
"resource": {
"id": "bd9cbf9d-a72b-4fd3-b302-b5e5e1925c16",
"resourceType": "PractitionerRole",
"active": true,
"practitioner": {
"type": "Practitioner",
"reference": "Practitioner/714c7b76-38b7-4618-929b-42d4c1c5d01b"
},
"organization": {
"type": "Organization",
"reference": "Organization/65585f90-7997-4c97-b7ea-6af6b67eaa24"
},
"meta": {
"versionId": "06595dad-552b-41fe-9e8c-3e36169b8430",
"lastUpdated": "2025-12-03T12:46:50.460Z"
}
},
"search": {
"mode": "include"
}
}
],
"total": 1,
"debug": {
"performance": {
"mainQueryDuration": 3.097,
"countQueryDuration": 2.371
}
},
"link": [
{
"relation": "self",
"url": "https://fhir-api.zapehr.com/Appointment?_count=1000&_include:iterate=Appointment:patient&_include:iterate=Patient:general-practitioner&_revinclude:iterate=PractitionerRole:practitioner"
},
{
"relation": "first",
"url": "https://fhir-api.zapehr.com/Appointment?_count=1000&_include:iterate=Appointment:patient&_include:iterate=Patient:general-practitioner&_offset=0&_revinclude:iterate=PractitionerRole:practitioner"
}
]
}As shown in the example above you can combine _include:iterate and _revinclude:iterate params in one request. But it is important to use the :iterate suffix if you need to get more than one layer of included resources, regular _include and _revinclude parameters will not work the same way.
On the other hand, the order of _include:iterate/_revinclude:iterate parameters is not important, as long as you keep the ResourceType:parameter values. So for example both ?_include:iterate=Appointment:patient&_include:iterate=Patient:general-practitioner&_revinclude:iterate=PractitionerRole:practitioner and ?_revinclude:iterate=PractitionerRole:practitioner&_include:iterate=Patient:general-practitioner&_include:iterate=Appointment:patient will return the same bundle.
Chaining
Chaining allows you to filter resources based on properties of referenced resources, without needing to fetch those referenced resources first. This is different from _include/_revinclude, which return referenced resources alongside your results. Chaining filters the primary results based on criteria that follow a reference chain.
For more details, see the FHIR chaining documentation (opens in a new tab).
Forward Chaining
Forward chaining uses dot notation to traverse references and filter on a property of the target resource. The syntax is reference-param.target-param=value. You can also specify the target resource type with reference-param:TargetType.target-param=value.
For example, suppose you have Slot resources that reference Schedule resources, which in turn reference Patient resources as actors. To find all slots where the schedule's actor is a patient named "Peter":
import { Slot } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const slotBundle/*: Bundle<Slot>*/ = await oystehr.fhir.search<Slot>({
resourceType: 'Slot',
params: [
{
name: 'schedule.actor:Patient.name',
value: 'Peter',
},
],
});
const slots/*: Slot[]*/ = slotBundle.unbundle();In this example, schedule is a search parameter on Slot that references a Schedule, actor is a search parameter on Schedule that references several resource types, and :Patient narrows the target to only Patient resources. Finally, .name=Peter filters on the patient's name.
Reverse Chaining (_has)
Reverse chaining uses the _has parameter to filter resources based on other resources that reference them. The syntax is _has:SourceResourceType:reference-param:search-param=value.
For example, to find all patients that have an Observation referencing them with a specific code:
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: '_has:Observation:patient:code',
value: '85354-9',
},
],
});
const patients/*: Patient[]*/ = patientBundle.unbundle();This query returns patients that are referenced by an Observation (via the patient search parameter) where the observation's code is 85354-9. Only the Patient resources are returned — the observations are used solely as filter criteria.
Combining Forward and Reverse Chains
You can combine forward and reverse chaining in a single query. For example, to find all RelatedPerson resources whose linked patient has an appointment at a specific location:
import { RelatedPerson } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your_access_token>",
});
const bundle/*: Bundle<RelatedPerson>*/ = await oystehr.fhir.search<RelatedPerson>({
resourceType: 'RelatedPerson',
params: [
{
name: 'patient._has:Appointment:patient:location',
value: 'Location/abc-123',
},
],
});
const relatedPersons/*: RelatedPerson[]*/ = bundle.unbundle();This query first follows the patient reference from RelatedPerson to Patient (forward chain), then checks if there is an Appointment that references that patient and has a specific location (reverse chain).
name Search Parameter
The name search parameter is used to match any of the string fields in a HumanName resource, including family, given, prefix, suffix, and/or text. A check on each field is performed separately, and a resource that has any matching field is added to the response.
Examples
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your access token>",
});
// corresponds to the SQL expression: LIKE "Anna Maria Juanita%"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name',
value: 'Anna Maria Juanita',
},
],
})).unbundle();
// corresponds to the SQL expression: = "Anna Maria Juanita"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:exact',
value: 'Anna Maria Juanita',
},
],
})).unbundle();
// corresponds to the SQL expression: LIKE "%Anna Maria Juanita%"
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:contains',
value: 'Anna Maria Juanita',
},
],
})).unbundle();Additional Features
You can perform a search on several alternatives for the parameter value by using a comma separator (which is equal to combining results by OR).
Examples
import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
const oystehr = new Oystehr({
accessToken: "<your access token>",
});
// will return all resources that match Anna, Mari, or Juanita
const patients/*: Patient[]*/ = (await oystehr.fhir.search<Patient>({
resourceType: 'Patient',
params: [
{
name: 'name:exact',
value: 'Anna,Maria,Juanita',
},
],
})).unbundle();FHIR R4B Search Conformance Matrix
The following tables document every search feature defined in the FHIR R4B search specification (opens in a new tab) and whether Oystehr supports it.
If you're interested in using an unsupported FHIR search feature, let us know at [email protected].
Search Parameter Types
| Parameter Type | Supported | Notes |
|---|---|---|
number | Yes | All comparison prefixes supported |
date | Yes | All comparison prefixes supported; handles instant, Period, and Timing data types |
string | Yes | Case-insensitive prefix match by default |
token | Yes | Supports [code], [system]|[code], |[code], and [system]| syntaxes |
reference | Yes | Supports local, absolute, canonical, and versioned references |
composite | Yes | Component values separated by $; components combined with AND logic |
quantity | Yes | All comparison prefixes supported; unit code matching supported |
uri | Yes | Exact URI matching by default |
special | Partial | near is not yet implemented |
Comparison Prefixes
Prefixes apply to number, date, and quantity parameter types.
| Prefix | Meaning | Supported |
|---|---|---|
eq | Equal (default) | Yes |
ne | Not equal | Yes |
gt | Greater than | Yes |
lt | Less than | Yes |
ge | Greater than or equal | Yes |
le | Less than or equal | Yes |
sa | Starts after | Yes |
eb | Ends before | Yes |
ap | Approximately (±10%) | Yes |
Search Modifiers by Parameter Type
String Modifiers
| Modifier | Supported | Notes |
|---|---|---|
| (no modifier) | Yes | Case-insensitive prefix match (e.g. name=Jon matches "Jonathan") |
:exact | Yes | Case-sensitive exact match |
:contains | Yes | Case-insensitive substring match |
:missing | Yes | true returns resources where the value is absent |
:text | No |
Token Modifiers
| Modifier | Supported | Notes |
|---|---|---|
| (no modifier) | Yes | Exact code match (case-insensitive by default) |
:exact | Yes | Case-sensitive exact match |
:contains | Yes | Substring match on code |
:not | Yes | Negation — returns resources that do not match |
:missing | Yes | true returns resources where the value is absent |
:text | No | Semantic text search on display or text |
:above | No | Code system hierarchy (ancestors) |
:below | No | Code system hierarchy (descendants) |
:in | No | Value set membership |
:not-in | No | Value set exclusion |
:of-type | No | Identifier type-based search |
Reference Modifiers
| Modifier | Supported | Notes |
|---|---|---|
| (no modifier) | Yes | Match by resource ID, [type]/[id], absolute URL, or canonical URL |
:exact | Yes | Exact reference match |
:missing | Yes | true returns resources where the reference is absent |
:identifier | Yes | Search by the target resource's business identifier ([system]|[value]) |
:[type] | No | Explicit type restriction (e.g. subject:Patient=123) |
:above | No | |
:below | No |
Date Modifiers
| Modifier | Supported | Notes |
|---|---|---|
:missing | Yes | true returns resources where the date is absent |
Number Modifiers
| Modifier | Supported | Notes |
|---|---|---|
:missing | Yes | true returns resources where the value is absent |
Quantity Modifiers
| Modifier | Supported | Notes |
|---|---|---|
:missing | Yes | true returns resources where the value is absent |
URI Modifiers
| Modifier | Supported | Notes |
|---|---|---|
| (no modifier) | Yes | Exact URI match |
:exact | Yes | Exact URI match (same as default) |
:missing | Yes | true returns resources where the URI is absent |
:above | No | Match URIs that are hierarchical parents |
:below | No | Match URIs that are hierarchical children |
Composite Modifiers
| Modifier | Supported | Notes |
|---|---|---|
| (no modifier) | Yes | Components separated by $, combined with AND |
:missing | No |
Common Search Parameters
These parameters apply to all resource types.
| Parameter | Supported | Notes |
|---|---|---|
_id | Yes | Filter by resource ID; supports :not and :missing modifiers; comma-separated values for OR |
_lastUpdated | Yes | Filter by last update timestamp; supports all date prefixes |
_tag | Yes | Filter by meta.tag; delegates to token search |
_profile | Yes | Filter by meta.profile; delegates to URI search |
_security | Yes | Filter by meta.security; delegates to token search |
_source | Yes | Filter by meta.source; delegates to URI search |
_has | Yes | Reverse chaining — filter by properties of resources that reference this one |
_type | No | Filter by resource type in whole-system searches |
_text | No | Full-text search on narrative |
_content | No | Full-text search on resource content |
_list | No | Filter by list membership |
_query | No | Named query |
_filter | No | Advanced filter syntax |
Search Result Parameters
| Parameter | Supported | Notes |
|---|---|---|
_sort | Yes | Sort by search parameter; prefix with - for descending; comma-separated for multiple sort keys |
_count | Yes | Page size (max 1000, default 1000) |
_offset | Yes | Skip N results for pagination |
_include | Yes | Include referenced resources; syntax: [SourceType]:[param] or [SourceType]:[param]:[TargetType] |
_revinclude | Yes | Include resources that reference the matched resources |
_include:iterate | Yes | Recursive include traversal up to 5 levels deep |
_revinclude:iterate | Yes | Recursive reverse include traversal up to 5 levels deep |
_total | Yes | Controls total count: none, estimate (default), or accurate |
_summary | Partial | Only true is supported (returns SUBSETTED resources); false, text, count, and data are not supported |
_elements | Yes | Restrict returned elements; supports element or Type.element syntax |
_contained | No | Search on contained resources |
_containedType | No | Filter contained resource types |
Chaining and Reverse Chaining
| Feature | Supported | Notes |
|---|---|---|
| Chained parameters | Yes | e.g. subject:Patient.name=Jon — search by properties of referenced resources |
Reverse chaining (_has) | Yes | e.g. _has:Observation:patient:code=1234 — filter by properties of resources that reference this one |
| Nested reverse chaining | Yes | e.g. _has:Observation:patient:_has:AuditEvent:entity:user=abc |
| Mixed forward and reverse chains | Yes | e.g. patient._has:Group:member:_id=102 |
Chaining in _sort | No | Sorting by chained parameters is not supported |
Logical Operations
| Feature | Supported | Notes |
|---|---|---|
| OR (comma-separated values) | Yes | e.g. name=Anna,Maria returns resources matching either value |
| AND (repeated parameters) | Yes | e.g. given=Jon&family=Snow returns resources matching both |
Paging
| Feature | Supported | Notes |
|---|---|---|
_count | Yes | Control page size (max 1000) |
_offset | Yes | Skip results for offset-based paging |
Bundle link relations | Yes | self, first, prev, next, last are returned as applicable |
Search via POST
| Feature | Supported | Notes |
|---|---|---|
POST [base]/[type]/_search with query string | Yes | Search parameters in the URL query string |
POST [base]/[type]/_search with form body | Yes | Content-Type: application/x-www-form-urlencoded body |
Other Features
| Feature | Supported | Notes |
|---|---|---|
| Compartment search | No | e.g. GET [base]/Patient/123/Observation |
| Whole-system search | No | e.g. GET [base]?_id=123 across all resource types |
| Canonical reference version search | Yes | e.g. url=http://example.org/ValueSet/123|1.0 |
| Versioned reference search | Yes | e.g. subject=Patient/123/_history/2 |
| Escaping special characters | Yes | \, and | are supported in parameter values |
| URL length limit | — | 10KB URL limit; use POST for larger queries |
Additional Resources
- Learn more about FHIR search in the FHIR Search documentation (opens in a new tab).
- Connect with us in the Oystehr Slack Workspace (opens in a new tab) for help crafting a tricky search query.