Errors
Every error response is application/problem+json (RFC 9457):
{ "type": "about:blank", "title": "Not Found", "status": 404, "detail": "No such resource for this tenant.", "code": "resource_not_found"}statusalways matches the HTTP status code.detailis human-readable and safe to log — it’s written for you to debug with, not for you to show a guest verbatim.codeis a stable, machine-readable string. Match your error handling oncode, never ondetailtext, which can change wording without notice.
A deliberate 404 policy
Section titled “A deliberate 404 policy”Cross-tenant access always returns 404, never 403 — if your key can’t
see a resource, the API responds exactly as if that resource doesn’t exist.
This also covers most authentication and authorization failures on this
API: an unknown key, a revoked key, the wrong key kind for a route, and a
publishable key’s origin not being on its allowlist all currently come back
as a generic 404. Only a missing or malformed Authorization header gets
a 401.
If you get an unexpected 404, check in this order: the resource ID,
whether you’re using the key kind (sk_/pk_) the route expects, and —
for a pk_ key — whether the request’s Origin header is on that key’s
allowlist.
Known gap: the 404/401/429 responses this auth layer produces
don’t carry a code field yet — only the four fields shown above. Adding
one is in scope for API-011. Endpoint-specific errors (quotes, guest OTP,
inventory) already carry stable codes today; see each endpoint’s page.
Common codes by endpoint
Section titled “Common codes by endpoint”| Endpoint | code |
Status |
|---|---|---|
GET /v1/availability, POST /v1/quotes |
resource_not_found |
404 |
POST /v1/quotes |
rate_plan_required, rate_plan_not_found |
400 / 404 |
POST /v1/quotes |
unavailable (carries reasons) |
409 |
POST /v1/quotes |
no_pricing_rule (carries missingDates), fx_rate_unavailable |
422 |
POST /v1/holds/{id}/otp |
hold_not_found, hold_not_held |
404 / 409 |
POST /v1/holds/{id}/otp/verify |
bad_code, expired, exhausted_attempts |
400 / 423 |
| guest-OTP routes | rate_limited |
429 |
POST /v1/holds |
idempotency_key_required, invalid_quote_token, quote_expired |
400 |
POST /v1/holds |
resource_locked, hold_conflict |
409 |
POST /v1/holds/{id}/confirm |
invalid_guest_token, wrong_reservation |
400 |
POST /v1/holds/{id}/confirm |
hold_not_found |
404 |
POST /v1/holds/{id}/confirm |
not_confirmable, payment_required (reserved, not yet triggered — see Holds and confirmation) |
409 |
GET/PATCH/DELETE /v1/bookings/{id} |
booking_not_found |
404 |
PATCH/DELETE /v1/bookings/{id} |
illegal_transition |
409 |
Full per-endpoint error lists live in the API Reference, generated straight from the checked-in OpenAPI spec.