API reference

Appointments

Bookings at a venue. 4 operations under /public/v1, with parameters, request bodies and example responses.

Paths are relative to the API host: https://sandbox-api.clivehealth.app for the sandbox, https://api.clivehealth.app for production. Send Authorization: Bearer <token> on every request (Getting started).

Operations

List appointments

GET/public/v1/appointments

Scope appointments:readOperation listAppointments

Ordered by updated_at then id. from and to filter on start_time.

Requires scope appointments:read.

Parameters

listAppointments parameters
NameInTypeDescription
limitqueryintegerPage size, 1 to 200. Default 50.
cursorquerystringOpaque cursor from the previous page's next_cursor.
updated_sincequerystring (date-time)ISO 8601 timestamp: only records updated at or after it. Lists are ordered by updated_at then id, so this plus cursor is a change feed.
member_idquerystring (uuid)
venue_idquerystring (uuid)
fromquerystring (date-time)Appointments starting at or after this time.
toquerystring (date-time)Appointments starting before this time.
statusquery"scheduled" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"

Responses

200A page of appointments.Returns AppointmentPage.

listAppointments 200 response
FieldTypeDescription
datarequiredarray of Appointment
idrequiredstring (uuid)
member_idrequiredstring (uuid)
venue_idrequiredstring (uuid)
practitioner_idrequiredstring (uuid)
start_timerequiredstring (date-time)
end_timerequiredstring (date-time)
duration_minutesrequiredinteger
typerequiredstringService or treatment type.
statusrequired"scheduled" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"
cancel_reasonrequiredstring or null
sourcerequiredstring or nullHow it was booked: partner_api, online_booking, manual, ...
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
next_cursorrequiredstring or nullPass as cursor to fetch the next page; null on the last page.
has_morerequiredboolean
Response 200JSON
{
  "data": [
    {
      "id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
      "member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
      "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
      "practitioner_id": "3f6b8d0a-2c4e-4f1a-9b3d-5e7f9a1c3e5b",
      "start_time": "2026-10-24T01:30:00.000Z",
      "end_time": "2026-10-24T02:00:00.000Z",
      "duration_minutes": 30,
      "type": "consultation",
      "status": "scheduled",
      "cancel_reason": null,
      "source": "partner",
      "created_at": "2026-10-01T00:00:00.000Z",
      "updated_at": "2026-10-24T02:15:09.123Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}
listAppointments error responses
StatusMeaning
400Malformed request or invalid cursor.
401Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN).
403The token lacks the scope this operation needs (INSUFFICIENT_SCOPE).
422Validation failed (VALIDATION_ERROR).
429Per-client rate limit exceeded (RATE_LIMITED).
500Unexpected error (INTERNAL_ERROR).

Every error body is the error envelope; branch on its code.

Book an appointment

POST/public/v1/appointments

Scope appointments:writeOperation createAppointment

Books the member at the venue. 409 SLOT_TAKEN when the practitioner (or every practitioner at the venue) is busy.

Requires scope appointments:write.

Parameters

createAppointment parameters
NameInTypeDescription
Idempotency-KeyrequiredheaderstringUnique key for this operation (a UUID is a good choice). Retrying with the same key and request replays the first response for 24 hours.

Request body AppointmentCreate

createAppointment request body
FieldTypeDescription
member_idrequiredstring (uuid)
venue_idrequiredstring (uuid)
start_timerequiredstring (date-time)ISO 8601 with offset; must be in the future.
duration_minutesintegerDefaults to the clinic's slot length.
typerequiredstring
practitioner_idstring (uuid)A specific practitioner; otherwise the first free practitioner at the venue is assigned.
Example requestJSON
{
  "member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
  "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "start_time": "2026-10-24T01:30:00.000Z",
  "duration_minutes": 30,
  "type": "consultation",
  "practitioner_id": "3f6b8d0a-2c4e-4f1a-9b3d-5e7f9a1c3e5b"
}

Responses

201The new appointment.Returns Appointment.

createAppointment 201 response
FieldTypeDescription
idrequiredstring (uuid)
member_idrequiredstring (uuid)
venue_idrequiredstring (uuid)
practitioner_idrequiredstring (uuid)
start_timerequiredstring (date-time)
end_timerequiredstring (date-time)
duration_minutesrequiredinteger
typerequiredstringService or treatment type.
statusrequired"scheduled" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"
cancel_reasonrequiredstring or null
sourcerequiredstring or nullHow it was booked: partner_api, online_booking, manual, ...
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
Response 201JSON
{
  "id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
  "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "practitioner_id": "3f6b8d0a-2c4e-4f1a-9b3d-5e7f9a1c3e5b",
  "start_time": "2026-10-24T01:30:00.000Z",
  "end_time": "2026-10-24T02:00:00.000Z",
  "duration_minutes": 30,
  "type": "consultation",
  "status": "scheduled",
  "cancel_reason": null,
  "source": "partner",
  "created_at": "2026-10-01T00:00:00.000Z",
  "updated_at": "2026-10-24T02:15:09.123Z"
}
createAppointment error responses
StatusMeaning
400Malformed request, invalid cursor, or missing Idempotency-Key (IDEMPOTENCY_KEY_REQUIRED).
401Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN).
403The token lacks the scope this operation needs (INSUFFICIENT_SCOPE).
409Conflict, or a request with the same Idempotency-Key is still in flight (IDEMPOTENCY_IN_PROGRESS).
422Validation failed (VALIDATION_ERROR), or the Idempotency-Key was used for a different request (IDEMPOTENCY_KEY_REUSED).
429Per-client rate limit exceeded (RATE_LIMITED).
500Unexpected error (INTERNAL_ERROR).

Every error body is the error envelope; branch on its code.

Get an appointment

GET/public/v1/appointments/{id}

Scope appointments:readOperation getAppointment

Requires scope appointments:read.

Parameters

getAppointment parameters
NameInTypeDescription
idrequiredpathstring (uuid)

Responses

200The appointment.Returns Appointment.

getAppointment 200 response
FieldTypeDescription
idrequiredstring (uuid)
member_idrequiredstring (uuid)
venue_idrequiredstring (uuid)
practitioner_idrequiredstring (uuid)
start_timerequiredstring (date-time)
end_timerequiredstring (date-time)
duration_minutesrequiredinteger
typerequiredstringService or treatment type.
statusrequired"scheduled" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"
cancel_reasonrequiredstring or null
sourcerequiredstring or nullHow it was booked: partner_api, online_booking, manual, ...
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
Response 200JSON
{
  "id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
  "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "practitioner_id": "3f6b8d0a-2c4e-4f1a-9b3d-5e7f9a1c3e5b",
  "start_time": "2026-10-24T01:30:00.000Z",
  "end_time": "2026-10-24T02:00:00.000Z",
  "duration_minutes": 30,
  "type": "consultation",
  "status": "scheduled",
  "cancel_reason": null,
  "source": "partner",
  "created_at": "2026-10-01T00:00:00.000Z",
  "updated_at": "2026-10-24T02:15:09.123Z"
}
getAppointment error responses
StatusMeaning
400Malformed request or invalid cursor.
401Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN).
403The token lacks the scope this operation needs (INSUFFICIENT_SCOPE).
404No such record in this clinic (NOT_FOUND).
422Validation failed (VALIDATION_ERROR).
429Per-client rate limit exceeded (RATE_LIMITED).
500Unexpected error (INTERNAL_ERROR).

Every error body is the error envelope; branch on its code.

Cancel an appointment

POST/public/v1/appointments/{id}/cancel

Scope appointments:writeOperation cancelAppointment

Cancelling an already-cancelled appointment returns it unchanged. Appointments in progress or completed can't be cancelled (409).

Requires scope appointments:write.

Parameters

cancelAppointment parameters
NameInTypeDescription
idrequiredpathstring (uuid)
Idempotency-KeyrequiredheaderstringUnique key for this operation (a UUID is a good choice). Retrying with the same key and request replays the first response for 24 hours.

Request body AppointmentCancel

cancelAppointment request body
FieldTypeDescription
reasonstring
Example requestJSON
{
  "reason": "Member requested"
}

Responses

200The cancelled appointment.Returns Appointment.

cancelAppointment 200 response
FieldTypeDescription
idrequiredstring (uuid)
member_idrequiredstring (uuid)
venue_idrequiredstring (uuid)
practitioner_idrequiredstring (uuid)
start_timerequiredstring (date-time)
end_timerequiredstring (date-time)
duration_minutesrequiredinteger
typerequiredstringService or treatment type.
statusrequired"scheduled" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"
cancel_reasonrequiredstring or null
sourcerequiredstring or nullHow it was booked: partner_api, online_booking, manual, ...
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
Response 200JSON
{
  "id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
  "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "practitioner_id": "3f6b8d0a-2c4e-4f1a-9b3d-5e7f9a1c3e5b",
  "start_time": "2026-10-24T01:30:00.000Z",
  "end_time": "2026-10-24T02:00:00.000Z",
  "duration_minutes": 30,
  "type": "consultation",
  "status": "scheduled",
  "cancel_reason": null,
  "source": "partner",
  "created_at": "2026-10-01T00:00:00.000Z",
  "updated_at": "2026-10-24T02:15:09.123Z"
}
cancelAppointment error responses
StatusMeaning
400Malformed request, invalid cursor, or missing Idempotency-Key (IDEMPOTENCY_KEY_REQUIRED).
401Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN).
403The token lacks the scope this operation needs (INSUFFICIENT_SCOPE).
404No such record in this clinic (NOT_FOUND).
409Conflict, or a request with the same Idempotency-Key is still in flight (IDEMPOTENCY_IN_PROGRESS).
422Validation failed (VALIDATION_ERROR), or the Idempotency-Key was used for a different request (IDEMPOTENCY_KEY_REUSED).
429Per-client rate limit exceeded (RATE_LIMITED).
500Unexpected error (INTERNAL_ERROR).

Every error body is the error envelope; branch on its code.