API errors and rate limits
What every error means, which requests to retry, and how much you can call.
Error shape
A failed request answers with an HTTP status of 400 or above and always the same JSON body. Branch on code: it is stable. message is written for people and may change. param names the parameter at fault, when there is one.
{
"error": {
"code": "invalid_parameter",
"message": "Unknown city for us: \"atlantis\". GET /locations/cities lists them.",
"param": "city"
}
}Codes
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_parameter | A parameter is missing or wrong; param names it | Fix the parameter named in param. For locations, take values from the location lists. Do not retry unchanged. |
| 400 | invalid_json | The body is not a JSON object | Send a JSON object with Content-Type: application/json. |
| 400 | invalid_request | An account rule refused the request (the message says which) | Read message: an account rule refused it (for example 50 presets, or a code already used). Do not retry unchanged. |
| 401 | unauthorized | No key, or a key that is not valid any more | Copy the current key from Settings → API; it may have been rotated. Send it as Authorization: Bearer …. |
| 402 | insufficient_balance | The balance does not cover a purchase | Top up the balance in the dashboard's wallet, or buy less. Get a price shows whether the balance covers it. |
| 403 | forbidden | The account email is not confirmed yet | Confirm the account's email, then retry. |
| 404 | not_found | No such endpoint, or no such object on your account | Check the path and the id: objects of other accounts are never visible. |
| 409 | conflict | The name is taken, or the Idempotency-Key is busy or was used elsewhere | Pick another name; for an Idempotency-Key that is still running, wait and send it again. |
| 409 | limit_reached | An account limit, such as 50 sub-users per product | Delete something you no longer need (a sub-user, a preset), then retry. |
| 429 | rate_limited | Too many requests; wait for Retry-After seconds | Wait for Retry-After seconds, then retry. Spread your calls, or ask for bigger pages. |
| 500 | internal_error | Our fault; retry, and tell support if it persists | Retry after a few seconds with backoff; purchases with the same Idempotency-Key. If it keeps failing, write to support with the X-Request-Id. |
Retries
Retry only what can succeed the second time: 429 after Retry-After, 500 and network errors with a growing pause (1, 2, 4, 8 seconds). A 4xx other than 429 will fail the same way until the request changes.
Reading endpoints are safe to repeat. Two writing endpoints accept an Idempotency-Key header so that a repeat cannot act twice: Create a sub-user and Buy traffic. Send any unique string up to 64 characters (a UUID); the same request with the same key within 24 hours gets the first answer back with Idempotent-Replayed: true. A request that failed is not stored, so after a fix (a top-up, say) the same key can be sent again.
Rate limits
| Limit | Value |
|---|---|
| Requests per key | 120 per minute |
| Purchases and balance codes per key | 10 per minute |
| Proxy checks per account | 1500 per 10 minutes, 100 per call |
| Requests with an invalid key, per address | 30 per minute |
| Proxy lines per call | 500 |
Every answer to a request with a valid key carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (a Unix time). Over the limit the answer is 429 with Retry-After in seconds. These limits are on API calls only: proxy connections through the gateway are not counted and have no thread limit.
Request id
Every answer has an X-Request-Id header. Log it with failures: support can find the request by it.
Proxy errors are different
The gateway that carries your proxy traffic answers with its own statuses (407 for a wrong login, 402 when traffic runs out, 502 when an exit fails), on gate.aeonproxy.com, not on the API. They are explained in gateway errors and the gateway documentation.