Errors & rate limits

Every error response includes a stable code and a human-readable error. Use the code to switch behaviour.

Status codes

HTTPMeaning
200Success (idempotent replay or read)
201Success (resource created / first-time effect)
400Validation error — body or query param invalid
401Missing / invalid / revoked API key
402Insufficient balance (e.g. tried to enter a raffle with too few WINZ)
403Scope-denied or tenant-suspended
404Resource not found
409State conflict (e.g. lootbox paused, tournament already closed)
429Rate limit exceeded
500Server error — safe to retry with same idempotency key
503Downstream temporarily unavailable — safe to retry

Error codes

CodeMeaning
AUTH_REQUIREDNo bearer token on the request
AUTH_INVALIDBearer present but unknown / revoked / wrong format
RATE_LIMITPer-tenant bucket emptied
NO_PLAYERPlayer resolution failed (unknown username)
NO_LOOTBOX / NO_RAFFLE / NO_JACKPOT / etc.Engagement record not found
NOT_ACTIVEThe entity is paused or completed
INSUFFICIENT_WINZPlayer has too few WINZ for the action (e.g. raffle entry cost)
NO_TICKETSRaffle draw attempted with zero entries
SERVICE_UNAVAILABLEDownstream service unreachable; retry safe

Rate limits

Token-bucket per tenant. Default capacity 200 burst + 50/sec sustained. Limits apply to the cumulative /v1/* surface, not per-endpoint.

On a 429, back off and retry. Implementations typically use jittered exponential backoff (200ms → 400ms → 800ms → …, with ±25% jitter).

Enterprise plans negotiate higher caps. If you sustain >50 req/sec, contact us before going live so we can pre-size your bucket.

Idempotency

Every write endpoint accepts idempotency_key in the body. Same key + same endpoint → original result. Different key + same body → new effect. Use a UUID per logical operation (not per HTTP attempt) — that way network retries naturally collapse.