Slot — Booking slot
The atomic building block of FHIR scheduling. A Slot is a time window inside a
Schedule with a free / busy status, ready to be consumed by
an Appointment.
Purpose of the resource
Slot represents a time interval within a Schedule that may be booked as an
Appointment. It's the minimum granularity in the FHIR model: a Slot carries a
start–end range, a status, and a reference to the parent
Schedule. An Appointment can consume a single Slot (a 15-minute visit) or multiple
consecutive Slots (a 90-minute procedure consumes six 15-minute Slots).
Slot mirrors Schedule
(its container) and Appointment
(the booking that consumes it). The crucial consistency rule: as soon as an
Appointment flips to booked, every Slot it references must flip to
busy. If the Appointment is cancelled, the Slot(s) revert to
free.
Key fields
The R5 StructureDefinition lists eleven top-level elements:
| Field | Type | Cardinality | Role |
|---|---|---|---|
identifier | Identifier[] | 0..* | External identifiers of the slot. |
serviceCategory | CodeableConcept[] | 0..* | Broad category of service offered on this Slot. Typically inherits from the parent Schedule. |
serviceType | CodeableReference[] | 0..* | Specific service type (first visit, follow-up, urgent care…). |
specialty | CodeableConcept[] | 0..* | Medical specialty (SNOMED CT). |
appointmentType | CodeableConcept[] | 0..* | Eligible Appointment type (WALKIN, ROUTINE, EMERGENCY… — v2-0276). |
schedule | Reference(Schedule) | 1..1 | Mandatory reference to the parent Schedule. |
status | code | 1..1 | Slot state. Modifier. |
start | instant | 1..1 | Slot start datetime (second precision + mandatory timezone). |
end | instant | 1..1 | Slot end datetime. |
overbooked | boolean | 0..1 | Indicates a Slot allows overbooking (two Appointments may reference the same Slot). |
comment | string | 0..1 | Human-readable notes for the front desk / app. |
Slot statuses
The status code is mandatory. Official ValueSet SlotStatus,
Required binding:
| Code | Meaning |
|---|---|
busy | The slot is taken: already booked by one or more Appointments. |
free | The slot is open: the client app may propose it to the patient. |
busy-unavailable | The slot cannot be booked — time off, lunch break, exceptional closure. Distinct from busy (which implies there is an Appointment). |
busy-tentative | The slot has a tentative booking — an Appointment in pending or proposed. |
entered-in-error | Slot created in error. Skip. |
JSON example
A free 15-minute slot in Dr Adam Careful's Schedule on 22 May 2026 at 09:15 Paris time. Category "General Practice", type "Walk-in".
{
"resourceType": "Slot",
"id": "example",
"identifier": [{
"system": "http://example.org/identifiers/slots",
"value": "123"
}],
"serviceCategory": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/service-category",
"code": "17",
"display": "General Practice"
}]
}],
"serviceType": [{
"concept": {
"coding": [{
"system": "http://example.org/service-type",
"code": "57",
"display": "Immunization"
}]
}
}],
"appointmentType": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0276",
"code": "WALKIN",
"display": "A previously unscheduled walk-in visit"
}]
}],
"schedule": { "reference": "Schedule/example" },
"status": "free",
"start": "2026-05-22T09:15:00+02:00",
"end": "2026-05-22T09:30:00+02:00",
"comment": "15-minute slot — first appointment of the morning."
} Worth pointing out in this example:
scheduleis1..1— an orphan Slot doesn't exist: it always belongs to a Schedule.- The
serviceCategory,serviceType,specialtyfields duplicate the parent Schedule — their presence here enables fine-grained indexing (e.g. a "General Practice" Schedule with a few "Vaccination"-purpose Slots). appointmentTypeconstrains which Appointment type may consume this Slot — useful to reserve a band for new patients.statusisfree: the patient app may propose it.
Searching slots
Typical queries from a booking app:
GET /Slot?schedule=Schedule/example&status=free&start=ge2026-05-22— free slots in a given Schedule from a date.GET /Slot?schedule.actor=Practitioner/example&status=free— free slots across all Schedules for a practitioner (FHIR chained search).GET /Slot?service-type=57&specialty=394814009&status=free— search by service type and specialty, practitioner-agnostic.GET /Slot?_count=20&_sort=start&status=free&start=ge2026-05-22&start=lt2026-05-29— pagination + sort + one-week window.
The Argonaut Scheduling and US Core Scheduling profiles encapsulate those queries in a
$find operation exposed on the server root or on Schedule.
Common pitfalls
- Slot without
schedule—1..1cardinality. Rejected by the validator. - Slot where
end<start— invariant slt-1: end must be later than start. Silent error on some servers. - Slot and Appointment out of sync — a
bookedAppointment referencing afreeSlot is a business inconsistency. Synchronization is the server's responsibility — typically a database trigger or a FHIR PreCreate hook. - Slot
busywithout an Appointment — the inverse: a slot marked busy with no Appointment referencing it. Only legitimate withstatus=busy-unavailable(break, time off). - Slot overlaps — FHIR does not forbid two overlapping Slots. Legitimate to model a pairing ("two clinicians on the same hour") but to avoid in a single-practitioner agenda.
- Missing timezone — the FHIR
instanttype requires an offset.2026-05-22T09:15:00is rejected. overbooked=truebutstatus=busy— semantic inconsistency. An overbooked Slot should not flip tobusywhile it still accepts additional bookings.
Related resources
- Schedule — the parent container of the Slot.
- Appointment — the booking that consumes one or more Slots.
- Practitioner, PractitionerRole, Location, Device — actors of the parent Schedule.
See also: the FHIR R5 index.