Book with $book (recommended)
The recommended way to book against a free slot is the POST /fhir/Appointment/$book operation. It takes { slotId, participant[], reasonCode?, comment? }, atomically verifies the slot is free, checks each participant for schedule conflicts, creates the Appointment with status: "booked" (with start/end taken from the slot), and flips the Slot to busy.
curl -X POST https://api.esus.health/fhir/Appointment/\$book \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"slotId": "c1a2e3d4-5b6f-7890-abcd-ef1234567890",
"participant": [
{
"actor": { "reference": "Patient/3fa85f64-5717-4562-b3fc-2c963f66afa6", "display": "John Doe" },
"required": "required",
"status": "accepted"
},
{
"actor": { "reference": "Practitioner/a7b1c2d3-e4f5-6789-abcd-ef0123456789", "display": "Dr. Sarah Johnson" },
"required": "required",
"status": "accepted"
}
],
"reasonCode": [{
"coding": [{ "system": "http://snomed.info/sct", "code": "185349003", "display": "Encounter for check up" }]
}],
"comment": "Annual wellness checkup"
}'
If the slot is not free, $book returns ValidationError (HTTP 400). If any participant has an overlapping appointment, it also returns 400 for double booking.
Create an Appointment manually
You can also create the Appointment directly with a POST /fhir/Appointment. The slot[] and participant[].actor references use the standard FHIR reference shape.
Heads up: a manual
POST /fhir/Appointmentthat carriesslot[]does NOT flip the Slot tobusy— only$bookdoes. If you use manual create, your application is responsible for updating the Slot’s status separately. For bookings against a slot, prefer$book.
curl -X POST https://api.esus.health/fhir/Appointment \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"status": "booked",
"serviceType": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/service-type",
"code": "124",
"display": "General Practice"
}]
}],
"appointmentType": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0276",
"code": "NORMAL",
"display": "Normal appointment"
}]
},
"slot": [
{ "reference": "Slot/c1a2e3d4-5b6f-7890-abcd-ef1234567890" }
],
"participant": [
{
"actor": {
"reference": "Patient/3fa85f64-5717-4562-b3fc-2c963f66afa6",
"display": "John Doe"
},
"required": "required",
"status": "accepted"
},
{
"actor": {
"reference": "Practitioner/a7b1c2d3-e4f5-6789-abcd-ef0123456789",
"display": "Dr. Sarah Johnson"
},
"required": "required",
"status": "accepted"
}
],
"reasonCode": [{
"coding": [{
"system": "http://snomed.info/sct",
"code": "185349003",
"display": "Encounter for check up"
}]
}],
"description": "Annual wellness checkup",
"minutesDuration": 30
}'
Appointment Status Flow
proposed → pending → booked → arrived → fulfilled
↘ cancelled
↘ noshow
The valid transitions are fixed on the server: proposed → {pending, cancelled}, pending → {booked, cancelled}, booked → {arrived, cancelled, noshow}, arrived → {fulfilled, cancelled}. Any other transition returns ValidationError (HTTP 400).
| Status | Meaning |
|---|---|
proposed | Appointment suggested but not confirmed |
pending | Awaiting confirmation |
booked | Confirmed |
arrived | Patient has arrived |
fulfilled | Appointment completed |
cancelled | Appointment cancelled |
noshow | Patient did not attend |
checked-in | Enum literal, but NOT reachable via a status update (no transition leads to it) |
waitlist | Only valid at creation; no outgoing transition (see Waitlist Management) |
entered-in-error | Recorded in error |
Register Patient Arrival
Use PATCH to update only the status (PATCH accepts a partial Appointment body — see Getting Started → CRUD):
curl -X PATCH https://api.esus.health/fhir/Appointment/d4e5f6a7-b8c9-0123-def4-567890abcdef \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{ "status": "arrived" }'
Cancel an Appointment
curl -X PATCH https://api.esus.health/fhir/Appointment/d4e5f6a7-b8c9-0123-def4-567890abcdef \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"status": "cancelled",
"cancelationReason": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/appointment-cancellation-reason",
"code": "PATIENT",
"display": "Patient cancelled"
}]
}
}'