Limits and Errors
The limits the relay applies and the answers a client sees when it hits one, for the REST API and for /wss.
Error shape
Most REST errors have this shape:
{"detail": "<text>"}- A validation error is
422withdetailas a list of{loc, msg, type}items. - Some errors from the application layer use
{"error": "<text>"}.
Read the status code first and the text second: the text is for people.
Status codes
| Status | Meaning |
|---|---|
| 400 | The request is wrong for this state: a missing or wrong current_password or totp_code, an agent over the plan limit (Agent limit reached …) |
| 401 | No token (API token required), an unknown or expired token (API token has expired.), a wrong password, or a missing 2FA code (2FA code required with X-2FA-Required: true) |
| 403 | Allowed in principle, refused now: Account is disabled, a token type that cannot use the account API, Telegram not linked, an admin action that needs a fresh step-up (admin_reauth_required) |
| 404 | No such object, or it is not yours |
| 409 | A conflict: Agent with this ID already registered, a taken username, seats_full or quarter_budget_used on the beta, or secret_unreadable |
| 413 | A preferences blob over 8 KiB |
| 422 | The body does not validate |
| 426 | GET /wss without a WebSocket upgrade |
| 429 | A rate limit or a lockout; see below |
| 502, 503, 504 | From the site's proxy: the relay answered badly, is down, or timed out |
secret_unreadable (409) means the relay cannot decrypt a stored secret, usually because its encryption key changed. Ask an administrator to reset your 2FA, or reissue the agent's key ( Tokens ).
Rate limits
The limits are per client IP, as a token bucket (requests per second, burst). A refused request gets 429 and this body:
{"detail": "Rate limit exceeded"}The headers of the answer:
X-RateLimit-RemainingX-RateLimit-ResetRetry-After
| Preset | Rate | Burst | Used by |
|---|---|---|---|
| Auth | 3 per second | 5 | Login, registration, password reset, 2FA and re-authentication endpoints, account deletion |
| Default | 10 per second | 50 | Agents, targets, profile, preferences, admin lists |
| Relaxed | 100 per second | 500 | Light read endpoints |
Endpoints with no limit in the generated list (docs/api/rest-api.md of the relay) are not limited by IP. When Redis is down the limits fail open and the relay logs rate_limiter_fail_open.
Behind a reverse proxy the relay trusts X-Forwarded-For and X-Real-IP only from the peers named in these settings:
WAKELINK_FORWARDED_ALLOW_IPSTRUSTED_PROXY_IPS
Lockouts
| What | Rule |
|---|---|
| Wrong password | The fifth wrong password locks the account for 30 minutes, then 60, 90 and so on up to 24 hours |
| Wrong 2FA code | More than five in 15 minutes: 429 until the window passes |
| Unknown token | Five per hour from one IP: 429 |
| /wss authentication | Five failures from one IP in 300 seconds: locked for 600 seconds |
Plan limits
| Limit | Where it shows |
|---|---|
| Agents per plan | 400 on POST /agents and POST /agents/virtual |
| Wakes per day on Free | WAKE_LIMIT on /wss |
Numbers are on Plans .
WebSocket errors
Messages of this form on /wss:
{"type": "error", "code": "…", "error": "…"}| Code or text | When |
|---|---|
| INVALID_BINARY_ENVELOPE | The binary message does not start with 0x02, a length and a route ID |
| INVALID_BINARY_FRAME | The frame is not 0xAE 0x01, is shorter than 21 bytes or longer than 4096 |
| INVALID_ROUTE | No agent ID, or the connection is not signed in |
| ACCESS_DENIED | The agent is not on your account |
| RATE_LIMITED | More than 10 commands per minute for that agent; retry_after is 30 |
| WAKE_LIMIT | The Free daily wake limit; retry_after is the seconds until midnight UTC |
| AGENT_NOT_CONNECTED | The agent has no relay connection; check Troubleshooting (agent offline) |
| Agent timeout | The agent did not answer within 30 seconds |
| LIMIT_EXCEEDED | The session passed 10000 requests; the connection closes with 1008 |
| MESSAGE_TOO_LARGE | The message could not be read; the connection closes with 1009 |
| Payload too large | A JSON relay payload over 4096 bytes |
Authentication failures use auth_response with status: "failed" ( WebSocket ). For an offline agent see Troubleshooting .
Aegis errors
An agent drops a packet it cannot accept:
- a bad authentication tag;
- a replayed or too old sequence number;
- an unknown session;
- a sequence jump over 1000.
The Aegis library defines the codes E001 to E008, in this order:
INVALID_PACKETAUTH_FAILEDSEQ_OUT_OF_ORDERAEAD_AUTH_FAILEDKEY_EXCHANGE_FAILEDREPLAY_DETECTEDTIMEOUTDEVICE_BUSY
A client that sees repeated failures should open a new session ( Aegis Wire Format ).
- Sign-in and 2FA — the account lockout in context
- WebSocket Protocol — the messages around these errors
- Troubleshooting — symptom, then what to do