Skip to main content

Schedule $find

Alpha

The $find operation is currently in alpha. It supports only Schedules with a single actor.

The $find operation takes a Schedule and a HealthcareService and returns a bundle of available (free) Slot resources within a specified time range. Slots are computed dynamically from the Schedule's SchedulingParameters extension — no Slots need to be pre-generated.

Use Cases

  • Patient-facing booking flows: Show a patient the available time windows for a given provider or location
  • Availability checks: Determine whether a provider has open time before attempting to book
  • Multi-provider scheduling: Query multiple Schedules and intersect results to find shared availability

Invoke the $find operation

[base]/R4/Schedule/[id]/$find
import { MedplumClient } from '@medplum/core';
import type { Bundle, Parameters, Slot } from '@medplum/fhirtypes';

const medplum = new MedplumClient();

const result = await medplum.post(
medplum.fhirUrl('Schedule', 'my-schedule-id', '$find'),
{
resourceType: 'Parameters',
parameter: [
{ name: 'start', valueDateTime: '2026-03-10T09:00:00-05:00' },
{ name: 'end', valueDateTime: '2026-03-10T17:00:00-05:00' },
{ name: 'service-type-reference', valueReference: { reference: "HealthcareService/my-healthcareservice-id"},
// Optional: limit number of results
{ name: '_count', valueInteger: 10 },
],
}
) as Parameters;

const bundle = result.parameter?.[0]?.resource as Bundle<Slot>;
const slots = bundle.entry?.map((e) => e.resource as Slot) ?? [];

Parameters

NameTypeDescriptionRequired
startdateTimeStart of the search window (inclusive)Yes
enddateTimeEnd of the search window (inclusive)Yes
service-type-referencereference(HealthcareService)The HealthcareService describing the type of appointment to be scheduled.Yes
_countintegerMaximum number of Slot resources to return. Defaults to 20. Maximum is 1000.No

Constraints

  • start must be before end
  • The search window cannot exceed 31 days
  • The Schedule must have exactly one actor reference
  • The Schedule's serviceType field must match the requested HealthcareService.type
  • The actor (Practitioner, Location, or Device) must have a timezone defined via the http://hl7.org/fhir/StructureDefinition/timezone extension

Output

Returns a Parameters resource wrapping a Bundle of Slot resources with status: free. The Slots are virtual — they are not persisted in the FHIR store.

Example Response

{
"resourceType": "Parameters",
"parameter": [
{
"name": "return",
"resource": {
"resourceType": "Bundle",
"type": "searchset",
"entry": [
{
"resource": {
"resourceType": "Slot",
"status": "free",
"start": "2026-03-10T09:00:00.000Z",
"end": "2026-03-10T10:00:00.000Z",
"schedule": { "reference": "Schedule/my-schedule-id" },
"serviceType": [
{
"coding": [
{
"code": "office-visit"
}
],
"extension": [
{
"url": "https://medplum.com/fhir/service-type-reference",
"valueReference": { "reference": "HealthcareService/my-healthcareservice-id"}
}
]
}
]
}
},
{
"resource": {
"resourceType": "Slot",
"status": "free",
"start": "2026-03-10T10:00:00.000Z",
"end": "2026-03-10T11:00:00.000Z",
"schedule": { "reference": "Schedule/my-schedule-id" },
"serviceType": [
{
"coding": [
{ "code": "office-visit" }
]
"extension": [
{
"url": "https://medplum.com/fhir/service-type-reference",
"valueReference": { "reference": "HealthcareService/my-healthcareservice-id"}
}
]
}
]
}
}
]
}
}
]
}

Availability Logic

$find calculates available windows by:

  1. Reading the Schedule's SchedulingParameters extension to determine recurring availability windows, slot duration, buffer times, and alignment constraints
  2. Fetching any existing Slot resources for the Schedule in the requested range (busy, busy-tentative, busy-unavailable, and free slots)
  3. Subtracting occupied time (including buffer windows around booked slots) from the availability windows
  4. Applying alignment intervals and offsets to produce valid start times
  5. Returning Slots 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 scheduleable for requested service type" } }]
}