{ "error": "<code>", ... }. Some include
a details object with extra context.
Authentication & authorisation
| Code | HTTP | Meaning |
|---|---|---|
missing_bearer_token | 401 | No Authorization: Bearer … header on a /me/* call. |
invalid_token | 401 | JWT could not be verified (signature, exp, iss mismatch, etc.). |
unknown_issuer | 401 | JWT’s iss doesn’t match any registered partner. |
invalid_claims | 401 | JWT verified but is missing required claims (sub, role). |
missing_partner_slug | 401 | /integrations/* request missing x-partner-slug. |
missing_signature | 401 | /integrations/* request missing x-signature. |
unknown_partner | 401 | x-partner-slug doesn’t match a known partner. |
invalid_signature_format | 401 | x-signature parse failed (missing t= or v1=). |
signature_expired | 401 | Timestamp outside the ±5 min window. |
invalid_signature | 401 | HMAC did not verify against the body. |
partner_disabled | 403 | Partner exists but is disabled in admin. |
forbidden | 403 | Caller has the wrong role for the endpoint. |
Consumer & redemption
| Code | HTTP | Meaning |
|---|---|---|
validation_failed | 400 | Zod body validation failed. issues array has details. |
voucher_not_found | 404 | No voucher with that ID. |
voucher_inactive | 422 | Voucher exists but is not currently active. |
voucher_not_wallet_flow | 422 | Tried to claim an instant-flow voucher. |
voucher_not_yet_valid | 422 | Voucher’s validFrom is in the future. |
voucher_expired | 422 | Past validUntil. |
voucher_out_of_scope | 403 | Voucher’s merchant or category is outside your partner allowlist. |
voucher_not_valid_at_outlet | 422 | Voucher not linked to this outlet. |
merchant_not_found | 404 | |
merchant_inactive | 422 | |
merchant_out_of_scope | 403 | |
outlet_not_found | 404 | |
outlet_inactive | 422 | |
outlet_pin_not_set | 422 | Outlet hasn’t configured a PIN yet — staff needs to set one. |
invalid_pin | 401 | Wrong 4-digit PIN. |
no_claim | 422 | Wallet voucher redeemed without first claiming. |
voucher_not_yet_applicable | 422 | Wallet voucher redeemed before its applicableFrom date. details: { applicableFrom }. |
voucher_no_longer_applicable | 422 | Wallet voucher redeemed after its applicableUntil date. details: { applicableUntil }. |
not_a_favorite | 403 | Voucher is favoritesOnly and user hasn’t favorited the merchant. |
limit_reached | 422 | Per-user cycle redemption count exceeded. details: { limit, used, cycleKey }. |
global_cap_reached | 422 | Shared cycle cap exhausted across all users for this voucher. details: { cap, used, cycleKey }. |
too_far | 422 | GPS distance > 150m. details: { distanceMeters, maxMeters }. |
codes_exhausted | 422 | Manual code pool empty — the merchant needs to upload more. |
code_generation_failed | 500 | Internal: auto code generator gave up. Treat as retryable. |
rate_limited | 429 | Too many redemption attempts. details: { retryAfterSeconds }. |
user_not_found | 404 | (DELETE) No user for (partner, externalUserId). |
upsert_failed | 500 | (POST users) Race-recovery failed; safe to retry. |