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 a total attribute on the response Bundle
  • estimate — Include an estimated total on the response Bundle; this is the default behavior
  • accurate — Include an exact total for 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 TypeSupportedNotes
numberYesAll comparison prefixes supported
dateYesAll comparison prefixes supported; handles instant, Period, and Timing data types
stringYesCase-insensitive prefix match by default
tokenYesSupports [code], [system]|[code], |[code], and [system]| syntaxes
referenceYesSupports local, absolute, canonical, and versioned references
compositeYesComponent values separated by $; components combined with AND logic
quantityYesAll comparison prefixes supported; unit code matching supported
uriYesExact URI matching by default
specialPartialnear is not yet implemented

Comparison Prefixes

Prefixes apply to number, date, and quantity parameter types.

PrefixMeaningSupported
eqEqual (default)Yes
neNot equalYes
gtGreater thanYes
ltLess thanYes
geGreater than or equalYes
leLess than or equalYes
saStarts afterYes
ebEnds beforeYes
apApproximately (±10%)Yes

Search Modifiers by Parameter Type

String Modifiers

ModifierSupportedNotes
(no modifier)YesCase-insensitive prefix match (e.g. name=Jon matches "Jonathan")
:exactYesCase-sensitive exact match
:containsYesCase-insensitive substring match
:missingYestrue returns resources where the value is absent
:textNo

Token Modifiers

ModifierSupportedNotes
(no modifier)YesExact code match (case-insensitive by default)
:exactYesCase-sensitive exact match
:containsYesSubstring match on code
:notYesNegation — returns resources that do not match
:missingYestrue returns resources where the value is absent
:textNoSemantic text search on display or text
:aboveNoCode system hierarchy (ancestors)
:belowNoCode system hierarchy (descendants)
:inNoValue set membership
:not-inNoValue set exclusion
:of-typeNoIdentifier type-based search

Reference Modifiers

ModifierSupportedNotes
(no modifier)YesMatch by resource ID, [type]/[id], absolute URL, or canonical URL
:exactYesExact reference match
:missingYestrue returns resources where the reference is absent
:identifierYesSearch by the target resource's business identifier ([system]|[value])
:[type]NoExplicit type restriction (e.g. subject:Patient=123)
:aboveNo
:belowNo

Date Modifiers

ModifierSupportedNotes
:missingYestrue returns resources where the date is absent

Number Modifiers

ModifierSupportedNotes
:missingYestrue returns resources where the value is absent

Quantity Modifiers

ModifierSupportedNotes
:missingYestrue returns resources where the value is absent

URI Modifiers

ModifierSupportedNotes
(no modifier)YesExact URI match
:exactYesExact URI match (same as default)
:missingYestrue returns resources where the URI is absent
:aboveNoMatch URIs that are hierarchical parents
:belowNoMatch URIs that are hierarchical children

Composite Modifiers

ModifierSupportedNotes
(no modifier)YesComponents separated by $, combined with AND
:missingNo

Common Search Parameters

These parameters apply to all resource types.

ParameterSupportedNotes
_idYesFilter by resource ID; supports :not and :missing modifiers; comma-separated values for OR
_lastUpdatedYesFilter by last update timestamp; supports all date prefixes
_tagYesFilter by meta.tag; delegates to token search
_profileYesFilter by meta.profile; delegates to URI search
_securityYesFilter by meta.security; delegates to token search
_sourceYesFilter by meta.source; delegates to URI search
_hasYesReverse chaining — filter by properties of resources that reference this one
_typeNoFilter by resource type in whole-system searches
_textNoFull-text search on narrative
_contentNoFull-text search on resource content
_listNoFilter by list membership
_queryNoNamed query
_filterNoAdvanced filter syntax

Search Result Parameters

ParameterSupportedNotes
_sortYesSort by search parameter; prefix with - for descending; comma-separated for multiple sort keys
_countYesPage size (max 1000, default 1000)
_offsetYesSkip N results for pagination
_includeYesInclude referenced resources; syntax: [SourceType]:[param] or [SourceType]:[param]:[TargetType]
_revincludeYesInclude resources that reference the matched resources
_include:iterateYesRecursive include traversal up to 5 levels deep
_revinclude:iterateYesRecursive reverse include traversal up to 5 levels deep
_totalYesControls total count: none, estimate (default), or accurate
_summaryPartialOnly true is supported (returns SUBSETTED resources); false, text, count, and data are not supported
_elementsYesRestrict returned elements; supports element or Type.element syntax
_containedNoSearch on contained resources
_containedTypeNoFilter contained resource types

Chaining and Reverse Chaining

FeatureSupportedNotes
Chained parametersYese.g. subject:Patient.name=Jon — search by properties of referenced resources
Reverse chaining (_has)Yese.g. _has:Observation:patient:code=1234 — filter by properties of resources that reference this one
Nested reverse chainingYese.g. _has:Observation:patient:_has:AuditEvent:entity:user=abc
Mixed forward and reverse chainsYese.g. patient._has:Group:member:_id=102
Chaining in _sortNoSorting by chained parameters is not supported

Logical Operations

FeatureSupportedNotes
OR (comma-separated values)Yese.g. name=Anna,Maria returns resources matching either value
AND (repeated parameters)Yese.g. given=Jon&family=Snow returns resources matching both

Paging

FeatureSupportedNotes
_countYesControl page size (max 1000)
_offsetYesSkip results for offset-based paging
Bundle link relationsYesself, first, prev, next, last are returned as applicable

Search via POST

FeatureSupportedNotes
POST [base]/[type]/_search with query stringYesSearch parameters in the URL query string
POST [base]/[type]/_search with form bodyYesContent-Type: application/x-www-form-urlencoded body

Other Features

FeatureSupportedNotes
Compartment searchNoe.g. GET [base]/Patient/123/Observation
Whole-system searchNoe.g. GET [base]?_id=123 across all resource types
Canonical reference version searchYese.g. url=http://example.org/ValueSet/123|1.0
Versioned reference searchYese.g. subject=Patient/123/_history/2
Escaping special charactersYes\, and | are supported in parameter values
URL length limit10KB URL limit; use POST for larger queries

Additional Resources