Rate limits

A per-key token bucket governs request rates; a hard monthly quota governs volume.

Two independent caps apply to every request, both per API key:

  1. A rate limit — a token bucket sized by your plan smooths short-term throughput.
  2. A monthly quota — the standard plan includes 10,000 requests per calendar month, enforced as a hard cap: requests past it are rejected until the month resets.

All keys see the same endpoints and data — the plan changes throughput and included volume, not features.

What counts

Every authenticated REST request draws one token and one unit of monthly quota. When your bucket is empty, further requests are rejected until it refills:

// 429 Too Many Requests
{ "error": "rate limit exceeded" }

Back off and retry after a short delay. Spikes are smoothed by the bucket's burst capacity; steady throughput above your refill rate is what triggers 429s.

When your monthly quota is used up, requests are rejected until the next calendar month starts:

// 429 Too Many Requests
{ "error": "monthly quota exceeded" }

Response headers

Every metered response tells you where you stand — no need to count client-side:

HeaderMeaning
X-RateLimit-LimitYour token bucket's capacity (the burst allowance).
X-RateLimit-RemainingWhole tokens left in the bucket after this request.
X-Quota-LimitYour monthly request quota (10,000 on the standard plan).
X-Quota-RemainingRequests left in the current calendar month.
X-Quota-ResetWhen the quota resets (RFC 3339, UTC — the start of next month).

Either kind of 429 also carries Retry-After — the number of seconds to wait before retrying (a second or two for a rate-limit 429; up to the month boundary for a quota 429).

Checking your usage

The headers above are authoritative per request; your dashboard shows the same request volume and remaining allowance for each key. Rate-limit and quota enforcement live in the API itself; the dashboard reads the same usage events the API records per request.

WebSocket connections

The WebSocket channel is metered differently from REST — a persistent connection isn't a stream of discrete requests, so the token-bucket model doesn't map cleanly onto it. It's a tier-gated feature, capped by concurrent connections rather than metered per message:

  • Concurrent-connection cap. On the standard plan a key may hold 5 concurrent connections (the cap is tier-based). Opening one past the cap is refused with an error frame (code: "connection_limit") followed by a close — not a queue.
  • Minting the ticket is one metered request. POST /v1/{game}/ws-token is an ordinary authenticated REST call, so it draws one token and one unit of monthly quota like any other. The messages pushed over the open connection afterwards are not billed — an open subscription accrues no per-message or per-heartbeat charges for its lifetime.
  • Disconnecting frees the slot immediately, including a heartbeat-timeout close.

Reuse one connection across many matches (that's what subscribe is for) rather than opening one per match, and reconnect with backoff rather than in a tight loop.

On this page