Appearance
Errors
Every error response is JSON with a stable error code and a human-readable message:
json
{ "error": "HOLD_EXPIRED", "message": "Hold has expired", "request_id": "…" }Branch on the HTTP status and the error code together: some codes come with more than one status (for example UNAUTHORIZED is 401 for a bad key and 403 for another partner's booking). Do not parse message; it can change. VALIDATION_ERROR responses also carry details, a list of { field, message, in }.
These are the codes a partner can receive. A code not listed here is not part of the contract; treat it by its HTTP status.
| HTTP | error | Meaning |
|---|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED | A cancel or refund (or partner hold cancel) was sent without idempotency_key. |
| 400 | INVALID_WEBHOOK_ENDPOINT | The webhook endpoint_url is not https, or its host does not resolve to a public address. |
| 400, 409 | SLOT_NOT_AVAILABLE | 409: the slot is held or booked, or overlaps one. 400: the window is not bookable at all (off the slot grid, outside opening hours, a resource the venue does not have); details.reason says why. |
| 400 | VALIDATION_ERROR | The request failed validation. details lists each field, the problem and where it was (body, query, params). |
| 401, 403 | UNAUTHORIZED | 401: the key is missing, unknown, revoked or expired. 403: the key is valid but the hold or booking belongs to another partner. |
| 403 | VENUE_NOT_AUTHORIZED | The key is valid and owns the hold or booking, but its venue is not (or no longer) granted to you. |
| 404 | BOOKING_NOT_FOUND | No booking with this id is visible to you (including another partner's booking). |
| 404 | HOLD_NOT_FOUND | No hold with this id is visible to you. |
| 404 | VENUE_NOT_FOUND | The venue does not exist or is not granted to you. The two cases are deliberately the same answer. |
| 404 | WEBHOOK_NOT_FOUND | No webhook subscription with this id belongs to you. |
| 409 | HOLD_EXPIRED | The hold passed hold_expiry_at. It cannot be confirmed; place a new hold. |
| 409 | IDEMPOTENCY_KEY_MISMATCH | This idempotency key was already used for a different request (another hold or booking, another operation, or different hold parameters). |
| 409 | INVALID_HOLD_STATE | The hold or booking is not in a state that allows this operation (for example confirming a cancelled hold). |
| 409 | PACKAGE_CREDIT_UNAVAILABLE | A credit-funded confirm found no active package you sold to this customer at this venue. Nothing was booked or deducted; the hold stays active. |
| 409 | TRANSFORMATION_CONFLICT | A shared or combined court conflicts with this window (for example the full pitch is booked while you hold a half). |
| 409 | VENUE_NOT_ACTIVE | The venue is paused or archived and takes no new holds. |
| 409 | WAITLIST_ENTRY_CONFLICT | The customer is already waiting for this venue, resource and date through another channel. Nothing was created or changed. |
| 429 | RATE_LIMIT_EXCEEDED | The key exceeded its rate limit. Wait Retry-After seconds. |
| 500 | INTERNAL_ERROR | An unexpected server error. |
Which operation returns which status is in the OpenAPI reference.
