Appointment $find | Medplum

On this page

Beta

The $find operation is currently in beta.

The $find operation takes a list of Schedule references and a HealthcareService reference and returns a bundle of proposed Appointment resources within a specified time range. Slots are computed dynamically from each SchedulingParameters extensions on each Schedule and HealthcareService — no Slots need to be pre-generated.

Use Cases

Invoke the $find operation

[base]/R4/Appointment/$find
import { MedplumClient } from '@medplum/core';

import type { Bundle, Appointment } from '@medplum/fhirtypes';

const medplum = new MedplumClient();

const url = medplum.fhirUrl('Appointment', '$find');

url.searchParams.append('start', '2026-03-10T09:00:00-05:00')

url.searchParams.append('end', '2026-03-10T17:00:00-05:00');

url.searchParams.append('service-type-reference', 'HealthcareService/my-healthcareservice-id')

url.searchParams.append('schedule', 'Schedule/my-schedule-id')

const bundle = await medplum.get<Bundle<Appointment>>(url);

const appointments = bundle.entry?.map((e) => e.resource as Appointment) ?? [];
curl -G 'https://api.medplum.com/fhir/R4/Appointment/$find' \
  -H "Authorization: Bearer MY_ACCESS_TOKEN" \
  --data-urlencode "start=2026-03-10T09:00:00-05:00" \
  --data-urlencode "end=2026-03-10T17:00:00-05:00" \
  --data-urlencode "service-type-reference=HealthcareService/my-healthcareservice-id" \
  --data-urlencode "schedule=Schedule/my-schedule-id"

Parameters

Name Type Description Required
start dateTime Start of the search window (inclusive) Yes
end dateTime End of the search window (inclusive) Yes
service-type-reference reference(HealthcareService) The HealthcareService describing the type of appointment to be scheduled. Yes
schedule reference(Schedule) A schedule to check for availability. May be passed multiple times with different schedules. Yes
_count integer Maximum number of Appointment resources to return. Defaults to 20. Maximum is 1000. No

Constraints

Output

Returns a Parameters resource wrapping a Bundle of Appointment resources with status: proposed.

The Appointments are virtual — they are not persisted in the FHIR store. Each Appointment has a contained attribute holding virtual (not persisted) Slot resources. These contained resources represent Slot resources that will be created if this Appointment is booked.

Example Response

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "return",
      "resource": {
        "resourceType": "Bundle",
        "type": "searchset",
        "entry": [
          {
            "resource": {
              "resourceType": "Appointment",
              "status": "proposed",
              "start": "2026-03-10T09:00:00.000Z",
              "end": "2026-03-10T10:00:00.000Z",
              "participant": [
                {
                  "actor": { "reference": "Practitioner/my-practitioner-id" },
                  "required": "required",
                  "status": "needs-action"
                }
              ],
              "serviceType": [
                {
                  "text": "Office Visit",
                  "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit" }]
                }
              ],
              "contained": [
                {
                  "resourceType": "Slot",
                  "status": "busy",
                  "start": "2026-03-10T09:00:00.000Z",
                  "end": "2026-03-10T10:00:00.000Z",
                  "serviceType": [
                    {
                      "text": "Office Visit",
                      "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit" }]
                    }
                  ],
                  "schedule": { "reference": "Schedule/my-schedule-id" }
                }
              ]
            }
          },
          {
            "resource": {
              "resourceType": "Appointment",
              "status": "proposed",
              "start": "2026-03-10T10:00:00.000Z",
              "end": "2026-03-10T11:00:00.000Z",
              "participant": [
                {
                  "actor": { "reference": "Practitioner/my-practitioner-id" },
                  "required": "required",
                  "status": "needs-action"
                }
              ],
              "serviceType": [
                {
                  "text": "Office Visit",
                  "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit" }]
                }
              ],
              "contained": [
                {
                  "resourceType": "Slot",
                  "status": "busy",
                  "start": "2026-03-10T10:00:00.000Z",
                  "end": "2026-03-10T11:00:00.000Z",
                  "serviceType": [
                    {
                      "text": "Office Visit",
                      "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit" }]
                    }
                  ],
                  "schedule": { "reference": "Schedule/my-schedule-id" }
                }
              ]
            }
          }
        ]
      }
    }
  ]
}

Availability Logic

$find calculates available windows by:

  1. Reading each Schedule's SchedulingParameters extension to determine recurring availability windows, slot duration, buffer times, and alignment constraints
  2. Fetching existing Slot resources for each Schedule in the requested range (busy, busy-tentative, busy-unavailable, and free slots)
  3. Adding time for existing Slot resources with status free
  4. Subtracting occupied time for existing Slot resources with status busy, busy-tentative, or busy-unavailable.
  5. Applying alignment intervals and offsets to produce valid start times
  6. Returning Appointments up to _count

See Defining Availability for full details on how SchedulingParameters are configured.

Error Responses

Invalid Time Range

{
  "resourceType": "OperationOutcome",
  "issue": [{ "severity": "error", "code": "invalid", "details": { "text": "Invalid search time range" }}]
}

Range Exceeds 31 Days

{
  "resourceType": "OperationOutcome",
  "issue": [{ "severity": "error", "code": "invalid", "details": { "text": "Search range cannot exceed 31 days" }}]
}

Actor Missing Timezone

{
  "resourceType": "OperationOutcome",
  "issue": [{ "severity": "error", "code": "invalid", "details": { "text": "No timezone specified" }}]
}

Schedule Has Multiple Actors

{
  "resourceType": "OperationOutcome",
  "issue": [{ "severity": "error", "code": "invalid", "details": { "text": "$find only supported on schedules with exactly one actor" }}]
}

Schedule.serviceType does not match HealthcareService.type

{
  "resourceType": "OperationOutcome",
  "issue": [{ "severity": "error", "code": "invalid", "details": { "text": "Schedule is not schedulable for requested service type" }}]
}

Beta Status

The Scheduling API is under active development. This beta release of the scheduling API is expected to gain additional capabilities.