API errors and rate limits
Every error code the API can return, what the rate limits are, and how to retry safely.
What an error looks like
Any response that is not HTTP 200 is an error. The body is JSON with a short, stable error code, sometimes with extra fields that belong to that code. Match on the code, never on the HTTP status alone.
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
{ "error": "rate_limited", "limit": 60, "windowSeconds": 60, "tier": 2 }Key, plan, and access errors
| Error | HTTP | Meaning and fix |
|---|---|---|
missing_api_key | 401 | No Authorization: Bearer header. Dashboard logins do not work on the API. |
invalid_api_key | 401 | The key is wrong or was revoked. Keys are case sensitive and exactly 64 characters. |
too_many_failed_attempts | 429 | 20 failed attempts (wrong key, or an IP that is not on the whitelist) from your IP in 10 minutes. Fix the key or the whitelist, or wait for Retry-After seconds. |
ip_not_allowed | 403 | Your IP whitelist is on and this request came from an IP that is not on it, or the list is empty. |
tier1_required | 403 | The account has no active paid plan, so every key is refused. It works again from the next request after you renew. |
tier2_required, tier3_required | 403 | Your plan does not include this endpoint. The body carries requiredTier and your current tier, for example { "error": "tier3_required", "requiredTier": 3, "tier": 2 }. See the plan table in Get started with the API. |
suspended, banned | 403 | The Console Client account is suspended or banned. |
maintenance | 503 | Console Client is in maintenance. Retry in a few minutes. |
Request errors
| Error | HTTP | Meaning and fix |
|---|---|---|
unknown_endpoint | 404 | The path or the HTTP method is not part of the API. Check the spelling and the method. |
invalid_json | 400 | The body is not valid JSON. |
body_too_large | 413 | The body is over 5 MB. |
invalid_request | 400 | A required field is missing or has the wrong type. |
invalid_account | 400 | The account ID is missing. |
not_found | 404 | No account with that ID. |
not_assigned, account_missing | 404 | The account is not running on a backend. Connect it first. |
not_connected | 409 | The account is not online. |
command_timeout, timeout | 504 | The account did not answer in time. It may be lagging or reconnecting. Retry once. |
server_error | 500 | Something failed on our side. Retry, and open a ticket if it keeps happening. |
Endpoint-specific codes, such as cooldown for connect or macro_not_found, are listed with their endpoint.
Rate limits
Your limits depend on your plan and belong to your account, not to a key: every key you create draws from the same allowance.
| Limit | Tier 1 | Tier 2 | Tier 3 | When you hit it |
|---|---|---|---|---|
| Requests per minute | 30 | 60 | 120 | 429 rate_limited with Retry-After. The body carries limit, windowSeconds and tier. |
| Requests in flight at once | 2 | 4 | 8 | 429 too_many_concurrent_requests with maxConcurrent and tier. A long poll counts as one for as long as it is open. |
| Limit | Value | When you hit it |
|---|---|---|
| Failed attempts | 20 per 10 minutes, per IP | 429 too_many_failed_attempts. Requests with a valid key from an allowed IP are not affected. |
Every authenticated response tells you where you stand:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per window on your plan: 30, 60 or 120. |
X-RateLimit-Remaining | Requests left in the current window, across all your keys. |
X-RateLimit-Reset | Unix time in seconds when the window resets. |
Retry-After | Only on a 429: how many seconds to wait. |
The limit is shared by everything that uses any of your keys, and refused requests count too, so a script that hammers a 429 only keeps itself locked out. A plan change applies from the next request; after a downgrade, requests already made in the current minute count against the lower limit.
Poll less, get more
| You want | Do this |
|---|---|
| Account status | One GET /accounts every 5 to 10 seconds covers every account. Do not call GET /accounts/{id} once per account. |
| Chat in real time | One GET /chat long poll with wait=25000 covers every account, at two or three requests a minute. |
| To know a macro finished | GET /macros/active every few seconds, or have the macro send a chat line or a Discord webhook as its last step. |
| A long click sequence | Build it as a macro and run it with one request. |
Retry safely
| Response | Retry? |
|---|---|
| 429 | Yes, after Retry-After seconds. For cooldown use cooldownRemaining. |
| 500, 503, 504 | Yes, with a growing delay: 1, 2, 4, 8 seconds, then give up and alert yourself. |
| 400, 401, 403, 404, 409 | No. The same request will fail the same way until you change something. |
Connect, disconnect, stop, and close are safe to repeat. Be careful repeating POST /chat/send after a timeout on your side: the first attempt may have gone through, and the account would say it twice.
Check the troubleshooting guide or return to all guides.