Scheduling | Medplum

Welcome to the Medplum Scheduling documentation

We currently support a range of scheduling operations that are available via the FHIR API. The following sections walk through the FHIR resources that are used to model scheduling and how the operations interact with them.

We like to separate scheduling into four main steps:

Step 1: Defining Service Types

Decide what types of appointments you would like to offer. Create a HealthcareService resource for each appointment type or service. Set a SchedulingParameters extension on each to define attributes like the length of the visit.

Mark which Schedule resources should be able to schedule appointments of that type by setting a reference to the HealthcareService in the Schedule.serviceType attribute.

Referencing a HealthcareService

In future FHIR revisions, Schedule.serviceType will have type CodeableReference(HealthcareService). In Medplum's R4 implementation, this is achieved by including an extension on a CodeableConcept in that attribute.

{
  resourceType: 'Schedule',
  actor: [
    {
      reference: 'Practitioner/dr-alice-smith',
    },
  ],
  serviceType: [
    {
      coding: [{ code: 'office-visit' }],
      extension: [
        {
          url: 'https://medplum.com/fhir/service-type-reference',
          valueReference: {
            reference: 'HealthcareService/5d02acfd-fbe8-4537-84e4-31f5116be105',
            display: 'Office Visit',
          },
        },
      ],
    },
  ],
};

Step 2: Defining Availability

The resources used to model availability for a provider, location, or device and the different service-specific scheduling parameters that can be defined.

The simplest version is a single schedule with a single practitioner and a single service type:

Practitioner

Schedule

Slot Status
Slot busy
Slot busy-unavailable
Appointment 1 booked

Step 3: Matching Availability

Based on the availability defined in the previous step, we can now find available appointment slots. This is done via the $find operation.

Operation Description Status
$find Find available appointment slots Beta

Step 4: Consuming Availability

Once a desired slot has been found, the appointment booking process can be handled in several steps.

Operation Description Status
$book Book an appointment in one step Beta
$hold Create a pending appointment Beta
$confirm Confirm a held appointment Beta
$cancel Cancel an appointment Beta

Key FHIR Resources

Resource Purpose
Schedule Represents a provider's, room's, or device's availability. Each Schedule belongs to exactly one actor.
Slot A specific time block on a Schedule. Only exists in the datastore for booked or blocked time — free slots are computed on demand.
Appointment A confirmed booking linking one or more Slots to a patient and provider.
HealthcareService Defines default scheduling parameters (duration, buffers, alignment) for a service type, shared across multiple providers.

Medplum Scheduling FHIR Model Design Decisions

Scheduling can be built in FHIR in many different ways. The key design decisions in Medplum's specific scheduling FHIR model are:

{
  url: 'http://hl7.org/fhir/StructureDefinition/timezone',
  valueCode: 'America/New_York'
}

Quickstart: Seed the Resources You Need

The minimum set of resources required for scheduling to work for a single provider is a Practitioner (the actor), a HealthcareService (the bookable appointment type and its shared parameters), and a Schedule (the actor's availability, linked to the service).

Seed Bundle: Practitioner + HealthcareService + Schedule

{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "fullUrl": "urn:uuid:2f8b7a10-9c3d-4e2a-b1f5-6d0a1c9e4b21",
      "resource": {
        "resourceType": "Practitioner",
        "name": [{ "given": ["Sarah"], "family": "Johnson", "prefix": ["Dr."] }],
        "identifier": [{ "system": "http://example.org/practitioners", "value": "dr-sarah-johnson" }],
        "extension": [{ "url": "http://hl7.org/fhir/StructureDefinition/timezone", "valueCode": "America/New_York" }]
      },
      "request": {
        "method": "POST",
        "url": "Practitioner",
        "ifNoneExist": "identifier=http://example.org/practitioners|dr-sarah-johnson"
      }
    },
    {
      "fullUrl": "urn:uuid:7c1e5d84-3b62-4a97-8e0d-92f4a6b13c58",
      "resource": {
        "resourceType": "HealthcareService",
        "name": "Office Visit",
        "type": [{
          "text": "Office Visit",
          "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit", "display": "Office Visit" }]
        }],
        "identifier": [{ "system": "http://example.org/serviceTypes", "value": "office-visit" }],
        "extension": [{
          "url": "https://medplum.com/fhir/StructureDefinition/SchedulingParameters",
          "extension": [{
            "url": "duration",
            "valueDuration": { "value": 1, "unit": "h", "system": "http://unitsofmeasure.org", "code": "h" }
          }, {
            "url": "alignmentInterval",
            "valueDuration": { "value": 15, "unit": "min", "system": "http://unitsofmeasure.org", "code": "min" }
          }, {
            "url": "alignmentTimezone",
            "valueCode": "America/New_York"
          }]
        }]
      },
      "request": {
        "method": "POST",
        "url": "HealthcareService",
        "ifNoneExist": "identifier=http://example.org/serviceTypes|office-visit"
      }
    },
    {
      "resource": {
        "resourceType": "Schedule",
        "active": true,
        "comment": "Dr. Sarah Johnson - Office Visit availability",
        "actor": [
          { "reference": "urn:uuid:2f8b7a10-9c3d-4e2a-b1f5-6d0a1c9e4b21", "display": "Dr. Sarah Johnson" }
        ],
        "serviceType": [{
          "text": "Office Visit",
          "coding": [{ "system": "http://example.org/appointment-types", "code": "office-visit" }],
          "extension": [{
            "url": "https://medplum.com/fhir/service-type-reference",
            "valueReference": {
              "reference": "urn:uuid:7c1e5d84-3b62-4a97-8e0d-92f4a6b13c58",
              "display": "Office Visit"
            }
          }]
        }],
        "extension": [{
          "url": "https://medplum.com/fhir/StructureDefinition/SchedulingParameters",
          "extension": [{
            "url": "service",
            "valueReference": {
              "reference": "urn:uuid:7c1e5d84-3b62-4a97-8e0d-92f4a6b13c58",
              "display": "Office Visit"
            }
          }, {
            "url": "availability",
            "extension": [{
              "url": "availableTime",
              "extension": [{ "url": "daysOfWeek", "valueCode": "mon" }, { "url": "daysOfWeek", "valueCode": "tue" }, { "url": "daysOfWeek", "valueCode": "wed" }, { "url": "daysOfWeek", "valueCode": "thu" }, { "url": "daysOfWeek", "valueCode": "fri" }, { "url": "availableStartTime", "valueTime": "09:00:00" }, { "url": "availableEndTime", "valueTime": "17:00:00" }]
            }]
          }]
        }]
      },
      "request": { "method": "POST", "url": "Schedule" }
    }
  ]
}

After uploading, you can immediately search for open slots with $find using service-type=office-visit, then book with $book. To add more providers, duplicate the Practitioner + Schedule pair.