API reference
Vouchers
Partner vouchers held by members, and their redemption at a venue. 3 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
- GET
/public/v1/vouchersList vouchers - GET
/public/v1/vouchers/{id}Get a voucher - POST
/public/v1/vouchers/redeemRedeem a voucher
List vouchers
/public/v1/vouchersScope vouchers:readOperation listVouchers
Ordered by updated_at then id.
Requires scope vouchers:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | Page size, 1 to 200. Default 50. |
cursor | query | string | Opaque cursor from the previous page's next_cursor. |
updated_since | query | string (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_id | query | string (uuid) | |
status | query | "issued" | "reserved" | "redeemed" | "void" | "expired" |
Responses
200A page of vouchers.Returns VoucherPage.
| Field | Type | Description |
|---|---|---|
datarequired | array of Voucher | |
idrequired | string (uuid) | |
member_idrequired | string (uuid) or null | |
providerrequired | string | |
external_idrequired | string or null | The partner's voucher id. |
coderequired | string | |
package_external_idrequired | string or null | |
statusrequired | "issued" | "reserved" | "redeemed" | "void" | "expired" | |
valid_fromrequired | string (date-time) or null | |
valid_torequired | string (date-time) or null | |
changes_usedrequired | integer | Reschedules and cancellations of the voucher's booking so far. |
purchased_atrequired | string (date-time) or null | |
created_atrequired | string (date-time) | |
updated_atrequired | string (date-time) | |
redemptionrequired | VoucherRedemption or null | |
redeemed_atrequired | string (date-time) | |
venue_idrequired | string (uuid) or null | |
appointment_idrequired | string (uuid) or null | |
methodrequired | "qr" | "code" | "api" | |
validationrequired | "online" | "offline" | "none" | online: confirmed with the provider; offline: the provider was unreachable and the clinic accepted it for later reconciliation. |
next_cursorrequired | string or null | Pass as cursor to fetch the next page; null on the last page. |
has_morerequired | boolean |
{
"data": [
{
"id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
"member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
"provider": "partner_v1",
"external_id": "MEM-0012345",
"code": "QS1792807209",
"package_external_id": "PKG-EXEC-2026",
"status": "issued",
"valid_from": "2026-10-01T00:00:00.000Z",
"valid_to": "2026-10-24T02:00:00.000Z",
"changes_used": 0,
"purchased_at": "2026-10-01T00:00:00.000Z",
"created_at": "2026-10-01T00:00:00.000Z",
"updated_at": "2026-10-24T02:15:09.123Z",
"redemption": null
}
],
"next_cursor": null,
"has_more": false
}| Status | Meaning |
|---|---|
| 400 | Malformed request or invalid cursor. |
| 401 | Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN). |
| 403 | The token lacks the scope this operation needs (INSUFFICIENT_SCOPE). |
| 422 | Validation failed (VALIDATION_ERROR). |
| 429 | Per-client rate limit exceeded (RATE_LIMITED). |
| 500 | Unexpected error (INTERNAL_ERROR). |
Every error body is the error envelope; branch on its code.
Get a voucher
/public/v1/vouchers/{id}Scope vouchers:readOperation getVoucher
Requires scope vouchers:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200The voucher.Returns Voucher.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
member_idrequired | string (uuid) or null | |
providerrequired | string | |
external_idrequired | string or null | The partner's voucher id. |
coderequired | string | |
package_external_idrequired | string or null | |
statusrequired | "issued" | "reserved" | "redeemed" | "void" | "expired" | |
valid_fromrequired | string (date-time) or null | |
valid_torequired | string (date-time) or null | |
changes_usedrequired | integer | Reschedules and cancellations of the voucher's booking so far. |
purchased_atrequired | string (date-time) or null | |
created_atrequired | string (date-time) | |
updated_atrequired | string (date-time) | |
redemptionrequired | VoucherRedemption or null | |
redeemed_atrequired | string (date-time) | |
venue_idrequired | string (uuid) or null | |
appointment_idrequired | string (uuid) or null | |
methodrequired | "qr" | "code" | "api" | |
validationrequired | "online" | "offline" | "none" | online: confirmed with the provider; offline: the provider was unreachable and the clinic accepted it for later reconciliation. |
{
"id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
"member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
"provider": "partner_v1",
"external_id": "MEM-0012345",
"code": "QS1792807209",
"package_external_id": "PKG-EXEC-2026",
"status": "issued",
"valid_from": "2026-10-01T00:00:00.000Z",
"valid_to": "2026-10-24T02:00:00.000Z",
"changes_used": 0,
"purchased_at": "2026-10-01T00:00:00.000Z",
"created_at": "2026-10-01T00:00:00.000Z",
"updated_at": "2026-10-24T02:15:09.123Z",
"redemption": null
}| Status | Meaning |
|---|---|
| 400 | Malformed request or invalid cursor. |
| 401 | Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN). |
| 403 | The token lacks the scope this operation needs (INSUFFICIENT_SCOPE). |
| 404 | No such record in this clinic (NOT_FOUND). |
| 422 | Validation failed (VALIDATION_ERROR). |
| 429 | Per-client rate limit exceeded (RATE_LIMITED). |
| 500 | Unexpected error (INTERNAL_ERROR). |
Every error body is the error envelope; branch on its code.
Redeem a voucher
/public/v1/vouchers/redeemScope vouchers:writeOperation redeemVoucher
Checks and redeems the voucher in one step, and checks the linked appointment in. A voucher is redeemed once: a second redeem is 409 VOUCHER_ALREADY_REDEEMED with details naming the venue, the person or client and the time. 404 VOUCHER_NOT_FOUND; 409 VOUCHER_NOT_REDEEMABLE (void, expired, not yet valid); 422 VOUCHER_REJECTED when the provider refused it online; 503 VOUCHER_PROVIDER_UNAVAILABLE when it could not be reached and the clinic refuses offline redemptions.
Requires scope vouchers:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Keyrequired | header | string | Unique 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 VoucherRedeem
| Field | Type | Description |
|---|---|---|
coderequired | string | The voucher code; case and spaces are ignored. |
venue_idrequired | string (uuid) | The branch where the member is being seen. |
appointment_id | string (uuid) | The booking the voucher is used for; it is checked in. Defaults to the voucher's own booking within 12 hours of now. |
{
"code": "QS1792807209",
"venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
"appointment_id": "8f6c2d4e-4c1b-4a8e-9d0f-1b2c3d4e5f60"
}Responses
201The redeemed voucher.Returns VoucherRedeemResult.
| Field | Type | Description |
|---|---|---|
voucherrequired | Voucher | A partner voucher held by a member. |
idrequired | string (uuid) | |
member_idrequired | string (uuid) or null | |
providerrequired | string | |
external_idrequired | string or null | The partner's voucher id. |
coderequired | string | |
package_external_idrequired | string or null | |
statusrequired | "issued" | "reserved" | "redeemed" | "void" | "expired" | |
valid_fromrequired | string (date-time) or null | |
valid_torequired | string (date-time) or null | |
changes_usedrequired | integer | Reschedules and cancellations of the voucher's booking so far. |
purchased_atrequired | string (date-time) or null | |
created_atrequired | string (date-time) | |
updated_atrequired | string (date-time) | |
redemptionrequired | VoucherRedemption or null | |
redeemed_atrequired | string (date-time) | |
venue_idrequired | string (uuid) or null | |
appointment_idrequired | string (uuid) or null | |
methodrequired | "qr" | "code" | "api" | |
validationrequired | "online" | "offline" | "none" | online: confirmed with the provider; offline: the provider was unreachable and the clinic accepted it for later reconciliation. |
appointment_idrequired | string (uuid) or null | |
checked_inrequired | boolean | The appointment was moved to checked_in by this redemption. |
{
"voucher": {
"id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
"member_id": "0b8e3c6a-2d4f-4e1b-9a7c-5d3e1f2a4b6c",
"provider": "partner_v1",
"external_id": "MEM-0012345",
"code": "QS1792807209",
"package_external_id": "PKG-EXEC-2026",
"status": "issued",
"valid_from": "2026-10-01T00:00:00.000Z",
"valid_to": "2026-10-24T02:00:00.000Z",
"changes_used": 0,
"purchased_at": "2026-10-01T00:00:00.000Z",
"created_at": "2026-10-01T00:00:00.000Z",
"updated_at": "2026-10-24T02:15:09.123Z",
"redemption": null
},
"appointment_id": null,
"checked_in": true
}| Status | Meaning |
|---|---|
| 400 | Malformed request, invalid cursor, or missing Idempotency-Key (IDEMPOTENCY_KEY_REQUIRED). |
| 401 | Missing, invalid or expired access token, or the API client was revoked (INVALID_TOKEN). |
| 403 | The token lacks the scope this operation needs (INSUFFICIENT_SCOPE). |
| 409 | Conflict, or a request with the same Idempotency-Key is still in flight (IDEMPOTENCY_IN_PROGRESS). |
| 422 | Validation failed (VALIDATION_ERROR), or the Idempotency-Key was used for a different request (IDEMPOTENCY_KEY_REUSED). |
| 429 | Per-client rate limit exceeded (RATE_LIMITED). |
| 500 | Unexpected error (INTERNAL_ERROR). |
Every error body is the error envelope; branch on its code.