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

List vouchers

GET/public/v1/vouchers

Scope vouchers:readOperation listVouchers

Ordered by updated_at then id.

Requires scope vouchers:read.

Parameters

listVouchers 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)
statusquery"issued" | "reserved" | "redeemed" | "void" | "expired"

Responses

200A page of vouchers.Returns VoucherPage.

listVouchers 200 response
FieldTypeDescription
datarequiredarray of Voucher
idrequiredstring (uuid)
member_idrequiredstring (uuid) or null
providerrequiredstring
external_idrequiredstring or nullThe partner's voucher id.
coderequiredstring
package_external_idrequiredstring or null
statusrequired"issued" | "reserved" | "redeemed" | "void" | "expired"
valid_fromrequiredstring (date-time) or null
valid_torequiredstring (date-time) or null
changes_usedrequiredintegerReschedules and cancellations of the voucher's booking so far.
purchased_atrequiredstring (date-time) or null
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
redemptionrequiredVoucherRedemption or null
redeemed_atrequiredstring (date-time)
venue_idrequiredstring (uuid) or null
appointment_idrequiredstring (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_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",
      "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
}
listVouchers 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.

Get a voucher

GET/public/v1/vouchers/{id}

Scope vouchers:readOperation getVoucher

Requires scope vouchers:read.

Parameters

getVoucher parameters
NameInTypeDescription
idrequiredpathstring (uuid)

Responses

200The voucher.Returns Voucher.

getVoucher 200 response
FieldTypeDescription
idrequiredstring (uuid)
member_idrequiredstring (uuid) or null
providerrequiredstring
external_idrequiredstring or nullThe partner's voucher id.
coderequiredstring
package_external_idrequiredstring or null
statusrequired"issued" | "reserved" | "redeemed" | "void" | "expired"
valid_fromrequiredstring (date-time) or null
valid_torequiredstring (date-time) or null
changes_usedrequiredintegerReschedules and cancellations of the voucher's booking so far.
purchased_atrequiredstring (date-time) or null
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
redemptionrequiredVoucherRedemption or null
redeemed_atrequiredstring (date-time)
venue_idrequiredstring (uuid) or null
appointment_idrequiredstring (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.
Response 200JSON
{
  "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
}
getVoucher 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.

Redeem a voucher

POST/public/v1/vouchers/redeem

Scope 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

redeemVoucher 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 VoucherRedeem

redeemVoucher request body
FieldTypeDescription
coderequiredstringThe voucher code; case and spaces are ignored.
venue_idrequiredstring (uuid)The branch where the member is being seen.
appointment_idstring (uuid)The booking the voucher is used for; it is checked in. Defaults to the voucher's own booking within 12 hours of now.
Example requestJSON
{
  "code": "QS1792807209",
  "venue_id": "c41f7a52-8d1e-4b2a-9f3c-6e5d4c3b2a10",
  "appointment_id": "8f6c2d4e-4c1b-4a8e-9d0f-1b2c3d4e5f60"
}

Responses

201The redeemed voucher.Returns VoucherRedeemResult.

redeemVoucher 201 response
FieldTypeDescription
voucherrequiredVoucherA partner voucher held by a member.
idrequiredstring (uuid)
member_idrequiredstring (uuid) or null
providerrequiredstring
external_idrequiredstring or nullThe partner's voucher id.
coderequiredstring
package_external_idrequiredstring or null
statusrequired"issued" | "reserved" | "redeemed" | "void" | "expired"
valid_fromrequiredstring (date-time) or null
valid_torequiredstring (date-time) or null
changes_usedrequiredintegerReschedules and cancellations of the voucher's booking so far.
purchased_atrequiredstring (date-time) or null
created_atrequiredstring (date-time)
updated_atrequiredstring (date-time)
redemptionrequiredVoucherRedemption or null
redeemed_atrequiredstring (date-time)
venue_idrequiredstring (uuid) or null
appointment_idrequiredstring (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_idrequiredstring (uuid) or null
checked_inrequiredbooleanThe appointment was moved to checked_in by this redemption.
Response 201JSON
{
  "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
}
redeemVoucher 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.