Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rate limits

This page describes the rate limits Open Play applies today and what to do when you get a 429. An important honesty note: there is no general rate limit per API key. Limits are placed on specific operations (sign-in, sign-up, chat, plugin command, socket connection); the other endpoints are unlimited and you must manage the load.

What you need to know

  • There is no general “N requests per minute” quota. For calls made with a server key, there is no general limit per key or per environment.
  • Counters are kept in Redis and if Redis cannot be reached, the limit is not applied (fail-open); the only exception is the audit-row ceiling noted below. Do not use the limit alone as a security control.
  • The Retry-After header exists only on the plugin 429 (60 s) and on 503 responses (30 s). The 429 of the core and identity endpoints carries no Retry-After; apply your own backoff.
  • The client IP is the key of the limits on the identity endpoints. If the reverse proxy does not forward the client IP, all players share the same bucket (production checklist).

Identity endpoints (the player sign-in line)

These limits are applied in the service layer; they are the same in REST itself. The window is fixed (it starts with the first request and the counter resets when the time expires; it is not a sliding window); an overage returns 429 and the plain text rate limited (no Retry-After).

BucketLimitWindowKeyWhich endpoints
Opening a guest3060 sClient IPPOST /v1/auth/sign-in/guest (re-sign-in counts too)
Email sign-in560 sClient IPPOST /v1/auth/sign-in/email (every attempt)
Failed sign-in lock10900 sAddress + IPWrong password attempts; the allowance is refunded on a successful sign-in; a wrong current password on a password change counts too
Sign-up (IP)1060 sClient IPPOST /v1/auth/sign-up/email, guest upgrade
Sign-up (session)3060 sSession ownerPOST /v1/auth/guest/upgrade/email
Sign-up (address)5900 sEmail addressSign-up and upgrade
Password change (IP)1060 sClient IPPOST /v1/auth/change-password
Password change (account)660 sPlayerPOST /v1/auth/change-password
Recovery (IP)560 sClient IPforgot-password, reset-password, sign-in/magic-link (the three endpoints share one bucket)
Recovery (address)5900 sEmail addressforgot-password, sign-in/magic-link
OAuth start3060 sClient IPsign-in/oauth/{provider}, link/{provider}
OAuth return6060 sClient IPcallback/{provider}

In addition:

LimitLimitKeyNote
Display name change10 / 3600 sPlayerPOST /v1/auth/session/display-name; an overage is 429
Account deletion attempt5 / 3600 sPlayerPOST /v1/auth/account/delete; an overage is 429
Failed sign-in audit row20 / 3600 sAccountDoes not reject the sign-in; it only throttles the background audit record. During a Redis outage the record is skipped (fail-closed)

Note

The guest opening bucket is per IP. If the reverse proxy does not forward the client IP, or many players connect from behind a NAT/dormitory network, the limit of 30 guests/minute fills quickly. If you plan a launch or a load test, verify IP forwarding.

Chat and notifications

LimitLimitWindowKeyWhen exceeded
Sending a chat message2010 sEnvironment + player429 in REST; message_rejected on the chat socket
Notification delivery6060 sEnvironment + playerDelivery is deferred (the provider is not hit), no error returns to the player

Plugin commands

Plugin commands and queries can be subject to per-minute budgets per player, per bucket. The plugin defines the budget; the server applies it with the same decision on the REST, realtime command, and gRPC paths. An overage arrives with the plugin envelope: 429, code: "rate_limited", retryable: true, Retry-After: 60.

The plugin that defines a budget today is package-ride: 6 to 60 commands per bucket in a 60 s window (for example delivery accept/start/complete 12, login bonus 10, quest reward and garage 30, collision/race bet 60). The bucket values are plugin-specific and may change; for exact numbers, see the plugin’s documentation. The operator can put some buckets into “observation” mode; in this mode an overage is only counted, and the command is not rejected.

In the Unity SDK, PluginClient.RetryAfter(error) returns 60 seconds for the plugin 429.

Realtime socket

LimitValueWhen exceeded
New connections per address30 / minuteThe upgrade is rejected
Open sockets per address8CapacityExceeded, the socket closes
Open sockets per player4CapacityExceeded, the socket closes
Per-connection frame rate40/s (a 160-frame burst allowance)CapacityExceeded (retryable: true), the socket closes

Details: reconnect and limits.

When you get a 429

HTTP/1.1 429 Too Many Requests
Content-Type: text/plain; charset=utf-8

rate limited

On a plugin endpoint:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
x-request-id: 0192a3b4-0000-7000-8000-0000000000d1

{"code":"rate_limited","message":"rate limited","retryable":true,"requestId":"0192a3b4-0000-7000-8000-0000000000d1"}
  1. If there is a Retry-After, wait that long; if not, use exponential backoff (for example 1, 2, 4, 8 s; upper bound 30 s) and add a random jitter.
  2. If the request is modifying, repeat with the same Idempotency-Key (idempotency and concurrency).
  3. For limits triggered by a user action (sign-in, sign-up), instead of an automatic retry show the user the wait time; on the password and sign-up endpoints an automatic retry extends the lock time.
  4. CrxClient (server key) retries a 429 on GET and keyed requests itself, respecting Retry-After (default 2 attempts).

Warning

A rule budget overage (rule budget exceeded: <rule>) also returns 429; this is not a rate limit but the rule engine budget (50 rules per command, 200 actions, 500 evaluation nodes, and chain depth 5). Retrying does not change the outcome; simplify the rule (game rules).

What you need to do on your side

Because there is no general server limit, you need to add protection under heavy load:

  • In server-to-server bulk jobs, limit concurrency (for example 5 to 10 requests at a time) and manage errors with backoff.
  • Measure the request rate per key on your own side; a single leaked key can make unlimited calls (security).
  • Before a launch, cache GET /v1/… reads (catalog endpoints support conditional reads with ETag and If-None-Match; do not poll per player more often than every 15 s).