Booking an Appointment
Booking an Appointment
The DELPHOS scheduling API provides a full appointment lifecycle from creation through completion or cancellation. Appointments follow a defined status machine with explicit transition endpoints.
Appointment Lifecycle
requested → confirmed → checked_in → in_progress → completed │ │ │ │ └───────────┴──────────────────→ no_show │ └──────────────────────────────────────────→ cancelled| Status | Description |
|---|---|
requested | Appointment created, awaiting confirmation |
confirmed | Confirmed by staff or provider |
checked_in | Patient has arrived and checked in |
in_progress | Appointment session is active |
completed | Appointment finished successfully |
no_show | Patient did not appear (from confirmed or checked_in) |
cancelled | Appointment cancelled (from requested, confirmed, or checked_in) |
Create an Appointment
POST /v1/scheduling/appointmentsRequest body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider_profile_id | UUID | Yes | — | UUID of the provider profile |
patient_id | UUID | Yes | — | UUID of the patient |
appointment_type_id | UUID | Yes | — | UUID of the appointment type |
location_id | UUID | Yes | — | UUID of the location |
start_time | datetime | Yes | — | Appointment start time (UTC) |
end_time | datetime | Yes | — | Appointment end time (UTC); must be after start_time |
room_id | UUID | No | null | Optional room assignment |
source | string | No | "api" | Booking channel: web, phone, whatsapp, api, walk_in, chatbot |
notes | string | No | null | Patient-visible notes |
internal_notes | string | No | null | Staff-only internal notes |
external_reference | string | No | null | External system reference (max 255 chars) |
metadata | object | No | {} | Additional metadata |
Status codes
| Code | Meaning |
|---|---|
201 | Appointment created successfully |
409 | Scheduling conflict — provider already has an appointment in this slot |
422 | Validation error (e.g. end_time before start_time, invalid source) |
curl -X POST "https://your-instance.delphos.app/v1/scheduling/appointments" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "provider_profile_id": "550e8400-e29b-41d4-a716-446655440001", "patient_id": "550e8400-e29b-41d4-a716-446655440002", "appointment_type_id": "550e8400-e29b-41d4-a716-446655440003", "location_id": "550e8400-e29b-41d4-a716-446655440004", "start_time": "2026-05-15T09:00:00Z", "end_time": "2026-05-15T09:30:00Z", "source": "web", "notes": "Follow-up for hypertension management" }'import httpx
response = httpx.post( "https://your-instance.delphos.app/v1/scheduling/appointments", headers={"x-api-key": "YOUR_API_KEY"}, json={ "provider_profile_id": "550e8400-e29b-41d4-a716-446655440001", "patient_id": "550e8400-e29b-41d4-a716-446655440002", "appointment_type_id": "550e8400-e29b-41d4-a716-446655440003", "location_id": "550e8400-e29b-41d4-a716-446655440004", "start_time": "2026-05-15T09:00:00Z", "end_time": "2026-05-15T09:30:00Z", "source": "web", "notes": "Follow-up for hypertension management", },)appointment = response.json()appointment_id = appointment["id"]Response fields (AppointmentResponse)
| Field | Type | Description |
|---|---|---|
id | UUID | Appointment UUID |
provider_profile_id | UUID | Provider profile UUID |
patient_id | UUID | Patient UUID |
appointment_type_id | UUID | Appointment type UUID |
location_id | UUID | Location UUID |
room_id | UUID or null | Room UUID |
series_id | UUID or null | Series UUID (for recurring appointments) |
start_time | datetime | Start time (UTC) |
end_time | datetime | End time (UTC) |
status | string | Current appointment status |
source | string | Booking channel |
notes | string or null | Patient-visible notes |
internal_notes | string or null | Staff-only notes |
external_reference | string or null | External system reference |
metadata | object | Additional metadata |
version | integer | Optimistic locking version |
created_at | datetime | Creation timestamp (UTC) |
updated_at | datetime | Last update timestamp (UTC) |
cancellation_reason | string or null | Reason provided when appointment was cancelled |
cancellation_policy_applied | string or null | Cancellation policy that was applied (e.g., late cancellation fee) |
Lifecycle Transitions
Each lifecycle action is a dedicated POST endpoint on the appointment.
Confirm
POST /v1/scheduling/appointments/{appointment_id}/confirmValid transition: requested → confirmed.
| Field | Type | Required | Description |
|---|---|---|---|
confirmed_by | string | No | Identifier of who confirmed |
Check in
POST /v1/scheduling/appointments/{appointment_id}/check-inValid transition: confirmed → checked_in.
| Field | Type | Required | Description |
|---|---|---|---|
checked_in_by | string | No | Identifier of who checked the patient in |
Start
POST /v1/scheduling/appointments/{appointment_id}/startValid transition: checked_in → in_progress. No request body required.
Complete
POST /v1/scheduling/appointments/{appointment_id}/completeValid transition: in_progress → completed.
| Field | Type | Required | Description |
|---|---|---|---|
notes | string | No | Completion notes |
Mark as no-show
POST /v1/scheduling/appointments/{appointment_id}/no-showValid transitions: confirmed → no_show, checked_in → no_show.
| Field | Type | Required | Description |
|---|---|---|---|
notes | string | No | No-show notes |
Cancel
POST /v1/scheduling/appointments/{appointment_id}/cancelValid transitions: requested → cancelled, confirmed → cancelled,
checked_in → cancelled.
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No | Cancellation reason text |
cancelled_by | string | No | Who cancelled: "patient", "provider", or "system" |
Cancellation policy:
| Timing | Policy |
|---|---|
| More than 24h before start | Free cancellation |
| 1h–24h before start | Late fee flag applied |
| Less than 1h before start | Not allowed (422) unless cancelled_by = "system" |
Reschedule
POST /v1/scheduling/appointments/{appointment_id}/rescheduleAtomic operation: cancels the original appointment and creates a new one in a single transaction.
| Field | Type | Required | Description |
|---|---|---|---|
new_start_time | datetime | Yes | New start time (UTC) |
new_end_time | datetime | Yes | New end time (UTC); must be after new_start_time |
new_location_id | UUID | No | New location (keeps original if omitted) |
new_room_id | UUID | No | New room assignment |
reason | string | No | Reschedule reason |
curl -X POST "https://your-instance.delphos.app/v1/scheduling/appointments/APPOINTMENT_ID/confirm" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"confirmed_by": "receptionist-001"}'import httpx
# Confirm appointmenthttpx.post( f"https://your-instance.delphos.app/v1/scheduling/appointments/{appointment_id}/confirm", headers={"x-api-key": "YOUR_API_KEY"}, json={"confirmed_by": "receptionist-001"},)
# Check in patienthttpx.post( f"https://your-instance.delphos.app/v1/scheduling/appointments/{appointment_id}/check-in", headers={"x-api-key": "YOUR_API_KEY"}, json={"checked_in_by": "receptionist-001"},)
# Start appointmenthttpx.post( f"https://your-instance.delphos.app/v1/scheduling/appointments/{appointment_id}/start", headers={"x-api-key": "YOUR_API_KEY"},)
# Complete appointmenthttpx.post( f"https://your-instance.delphos.app/v1/scheduling/appointments/{appointment_id}/complete", headers={"x-api-key": "YOUR_API_KEY"}, json={"notes": "Patient doing well. Follow-up in 3 months."},)All lifecycle endpoints return 200 with the updated AppointmentResponse
on success, 404 if the appointment is not found, and 422 if the
transition is invalid for the current status.
List and Retrieve Appointments
List appointments
GET /v1/scheduling/appointmentsUses cursor-based pagination. Returns AppointmentListResponse with items,
next_cursor, and has_more.
Get appointment detail
GET /v1/scheduling/appointments/{appointment_id}Returns AppointmentDetailResponse, which extends AppointmentResponse with
a status_history array of status change entries:
| Field | Description |
|---|---|
previous_status | Status before the change (null for creation) |
new_status | Status after the change |
changed_by | Who triggered the change |
reason | Reason for the change |
created_at | Timestamp of the change (UTC) |
Update an Appointment
PUT /v1/scheduling/appointments/{appointment_id}Supports partial updates for notes, internal_notes, metadata, and
room_id. Requires the current version for optimistic locking.
| Field | Type | Required | Description |
|---|---|---|---|
version | integer | Yes | Current version (prevents lost updates) |
notes | string | No | Updated patient-visible notes |
internal_notes | string | No | Updated staff-only notes |
metadata | object | No | Updated metadata |
room_id | UUID | No | Updated room assignment |
Returns 409 if the version does not match (optimistic lock conflict).
Complete Booking Workflow
-
Find available slots —
GET /v1/scheduling/slotsto search availability (see Calendar Management). -
Create appointment —
POST /v1/scheduling/appointmentswith the chosen slot times. -
Confirm —
POST /v1/scheduling/appointments/{id}/confirmwhen the patient confirms. -
Check in —
POST /v1/scheduling/appointments/{id}/check-inwhen the patient arrives. -
Start —
POST /v1/scheduling/appointments/{id}/startwhen the consultation begins. -
Complete —
POST /v1/scheduling/appointments/{id}/completewhen finished.