Skip to main content

Appointment $cancel

Beta

The $cancel operation is currently in beta.

The $cancel operation cancels an Appointment by atomically setting its status to cancelled and deleting all Slot resources it references in a single FHIR transaction. An optional cancelationReason records why the Appointment was canceled.

Use Cases​

  • Patient-initiated cancellation: Cancel a scheduled appointment at the patient's request and free the provider's time
  • Staff-initiated cancellation: Cancel an appointment from an admin or scheduling workflow
  • Automated cancellation: Programmatically cancel appointments based on external triggers (e.g., provider unavailability, EHR integration)

Invoke the $cancel operation​

[base]/R4/Appointment/:id/$cancel
import { MedplumClient } from '@medplum/core';
import type { Appointment, Parameters } from '@medplum/fhirtypes';

const medplum = new MedplumClient();

const appointment = await medplum.post<Appointment>(
medplum.fhirUrl('Appointment', 'my-appointment-id', '$cancel')
);

// Optionally, record why the Appointment was canceled
const appointmentWithReason = await medplum.post<Appointment>(
medplum.fhirUrl('Appointment', 'my-appointment-id', '$cancel'),
{
resourceType: 'Parameters',
parameter: [
{
name: 'cancelationReason',
valueCodeableConcept: {
coding: [
{
system: 'http://terminology.hl7.org/CodeSystem/appointment-cancellation-reason',
code: 'pat-cpp',
display: 'Patient: Canceled via Patient Portal',
},
],
},
},
],
} satisfies Parameters
);

Parameters​

The appointment to cancel is identified by the id in the URL.

NameTypeDescriptionRequired
cancelationReasonCodeableConceptThe coded reason the Appointment was canceled. Stored on Appointment.cancelationReason.No

Cancelation Reason​

When cancelationReason is provided, it is written to Appointment.cancelationReason on the canceled Appointment. When it is omitted, the field is left untouched.

note

FHIR R4 spells this element cancelationReason, with a single l. The operation parameter uses the same spelling as the resource element.

FHIR recommends coding this with the appointment-cancellation-reason CodeSystem, but any CodeableConcept is accepted.

{
"resourceType": "Parameters",
"parameter": [
{
"name": "cancelationReason",
"valueCodeableConcept": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/appointment-cancellation-reason",
"code": "pat-cpp",
"display": "Patient: Canceled via Patient Portal"
}
]
}
}
]
}

Constraints​

  • The Appointment must have status: booked or status: pending. All other statuses are rejected.
  • All Slot resources referenced by Appointment.slot must exist and be readable by the caller.

Output​

Returns 200 OK with the updated Appointment resource directly:

  • One Appointment with status: cancelled, and cancelationReason set if it was provided

All Slot resources that were referenced by the Appointment are deleted and do not appear in the response.

Example Response​

{
"resourceType": "Appointment",
"id": "my-appointment-id",
"status": "cancelled",
"cancelationReason": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/appointment-cancellation-reason",
"code": "pat-cpp",
"display": "Patient: Canceled via Patient Portal"
}
]
},
"start": "2026-03-10T09:00:00.000Z",
"end": "2026-03-10T10:00:00.000Z",
"participant": [
{ "actor": { "reference": "Practitioner/dr-smith" }, "status": "tentative" },
{ "actor": { "reference": "Patient/my-patient-id" }, "status": "accepted" }
]
}

Cancellation Logic​

$cancel performs the following steps atomically inside a database transaction, ensuring safety when concurrent scheduling requests are received.

  1. Reads the Appointment identified by the URL id
  2. Loads all Slot resources listed in Appointment.slot
  3. Validates that the Appointment's status is booked or pending
  4. Sets the Appointment's status to cancelled, along with cancelationReason if one was provided, and saves it
  5. Deletes all referenced Slots
  6. Returns the updated Appointment

Error Responses​

Appointment Not Found​

{
"resourceType": "OperationOutcome",
"issue": [{ "severity": "error", "code": "not-found", "details": { "text": "Not found" } }]
}

Appointment Not in Cancelable State​

{
"resourceType": "OperationOutcome",
"issue": [{ "severity": "error", "code": "invalid", "details": { "text": "Appointment cannot be canceled in 'arrived' status" } }]
}

Referenced Slot Not Found​

{
"resourceType": "OperationOutcome",
"issue": [{ "severity": "error", "code": "invalid", "details": { "text": "Loading slots failed" } }]
}