Scheduling Service — API Contracts
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 03 platform-services · API_PATH_CONVENTIONS
Common Headers
| Header | Value | Required |
|---|---|---|
Authorization | Bearer <JWT> | Yes |
Content-Type | application/json | Yes (mutations) |
Module entitlement guard: ehr.scheduling.
1. Appointments
| Method | Path | Description | Auth Roles |
|---|---|---|---|
| POST | /api/v1/appointments | Book appointment | admin, scheduler, physician, front-desk |
| POST | /api/v1/appointments/self | Patient self-book (patientId from JWT) | patient |
| GET | /api/v1/appointments?patientId=&status= | List patient appointments | authenticated |
| GET | /api/v1/appointments/calendar?from=&to=&facilityId=&providerIds= | Staff calendar view | admin, scheduler, physician, front-desk, nurse |
| GET | /api/v1/appointments/:id | Get by ID | authenticated |
| PUT | /api/v1/appointments/:id/status | Update status | admin, scheduler, physician, front-desk, nurse |
| PUT | /api/v1/appointments/:id/cancel | Staff cancel | admin, scheduler, physician, front-desk |
| PUT | /api/v1/appointments/:id/cancel-self | Patient cancel own | patient |
| PUT | /api/v1/appointments/:id/reschedule | Reschedule to new slot | admin, scheduler, physician, front-desk |
POST /api/v1/appointments — Book
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
patientId | UUID | Yes | |
slotId | UUID | Yes | Must be free |
appointmentType | string | No | ROUTINE/WALKIN/EMERGENCY etc. |
providerId | UUID | No | |
locationId | UUID | No | |
reason | string | No | |
allowDoubleBooking | boolean | No | Admin/scheduler only |
version | number | No | Required for reschedule |
Responses
| HTTP | Condition |
|---|---|
| 201 | Appointment created; returns AppointmentResponseDto with id, status: booked, slotId, patientId |
409 SLOT_NOT_AVAILABLE | Slot is not free |
409 DOUBLE_BOOKING_DETECTED | Overlap and override not permitted |
403 DOUBLE_BOOKING_OVERRIDE_DENIED | Override requested but caller lacks permission |
PUT /api/v1/appointments/:id/cancel
Request body: { "reason": "string", "version": number }
| HTTP | Error | Condition |
|---|---|---|
| 200 | Updated AppointmentResponseDto (status: cancelled) | |
| 409 | OPTIMISTIC_LOCK_CONFLICT | |
| 409 | INVALID_STATUS_TRANSITION |
PUT /api/v1/appointments/:id/reschedule
Request body: { "newSlotId": "uuid", "version": number, "reason?": "string" }
| HTTP | Error | Condition |
|---|---|---|
| 200 | Updated AppointmentResponseDto | |
| 409 | NEW_SLOT_NOT_AVAILABLE |
2. Schedules
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/schedules | Create schedule | admin, scheduler |
| GET | /api/v1/schedules?actorId= | List schedules | authenticated |
| GET | /api/v1/schedules/:id | Get schedule | authenticated |
| PUT | /api/v1/schedules/:id | Update schedule | admin, scheduler |
| POST | /api/v1/schedules/availability-preview | Preview expanded windows | admin, scheduler, physician, front-desk, nurse |
| POST | /api/v1/schedules/:id/exceptions | Add blocked window / holiday | admin, scheduler, physician, front-desk, nurse |
Schedule create/update body (selected fields)
| Field | Type | Notes |
|---|---|---|
actorId | UUID | Provider, location, or device |
actorType | provider|location|device | |
timezone | IANA string | e.g. Asia/Kabul (+04:30) |
availabilityPattern | object | { days: [{ dow: 0-6, start: "HH:MM", end: "HH:MM" }] } |
3. Slots
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/slots | Create slot | admin, scheduler |
| GET | /api/v1/slots?scheduleId=&from=&to= | Free slots for one schedule | authenticated |
| GET | /api/v1/slots/availability?providerId=&locationId=&from=&to= | Aggregated free slots (requires providerId and/or locationId + from/to) | authenticated |
| GET | /api/v1/slots/by-schedule/:scheduleId?status= | All slots for schedule | authenticated |
| GET | /api/v1/slots/:id | Get slot | authenticated |
| PUT | /api/v1/slots/:id | Update slot | admin, scheduler |
Slot status values: free | busy | blocked | entered-in-error
Availability aggregation notes
GET /api/v1/slots/availabilityrequires at leastproviderIdorlocationIdandfrom+to(ISO dates).- Returns consolidated free slots across all matching schedules.
- NFR-SCHED-001: p95 < 1 000 ms.
4. Waitlist
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/waitlist | Add to waitlist | admin, scheduler, clinician |
| GET | /api/v1/waitlist?status= | List entries | authenticated |
| GET | /api/v1/waitlist/:id | Get entry | authenticated |
| PUT | /api/v1/waitlist/:id/fulfill | Mark fulfilled | admin, scheduler |
| DELETE | /api/v1/waitlist/:id | Soft-delete | admin, scheduler |
Waitlist create body
| Field | Type | Required | Notes |
|---|---|---|---|
patientId | UUID | Yes | |
appointmentType | string | Yes | |
scheduleId | UUID | No | |
criteria | object | No | Free form matching hints |
priority | integer | No | Lower = higher priority; default: FIFO |
note | string | No |
5. HL7 v2 SIU Integration
| Method | Path | Description | Auth |
|---|---|---|---|
| POST | /api/v1/integration/hl7/siu | Inbound raw SIU message | admin |
Request body: { "message": "MSH|...\r..." }
Supports: S12 (create), S13 (modify), S15 (cancel).
6. FHIR R4
Base path: /fhir/R4 (same auth + ehr.scheduling).
| Interaction | Path | Notes |
|---|---|---|
| Read | GET /fhir/R4/Appointment/:id | |
| Search | GET /fhir/R4/Appointment?patient=Patient/:id&status= | |
| Read | GET /fhir/R4/Slot?schedule=Schedule/:id&status= | |
| Read | GET /fhir/R4/Schedule/:id |
FHIR Appointment status mapping: proposed, pending, booked, arrived, fulfilled, cancelled, noshow, entered-in-error.