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

StatusCodeMeaningWhat to do
400invalid_parameterA parameter is missing or wrong; param names itFix the parameter named in param. For locations, take values from the location lists. Do not retry unchanged.
400invalid_jsonThe body is not a JSON objectSend a JSON object with Content-Type: application/json.
400invalid_requestAn 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.
401unauthorizedNo key, or a key that is not valid any moreCopy the current key from Settings → API; it may have been rotated. Send it as Authorization: Bearer ….
402insufficient_balanceThe balance does not cover a purchaseTop up the balance in the dashboard's wallet, or buy less. Get a price shows whether the balance covers it.
403forbiddenThe account email is not confirmed yetConfirm the account's email, then retry.
404not_foundNo such endpoint, or no such object on your accountCheck the path and the id: objects of other accounts are never visible.
409conflictThe name is taken, or the Idempotency-Key is busy or was used elsewherePick another name; for an Idempotency-Key that is still running, wait and send it again.
409limit_reachedAn account limit, such as 50 sub-users per productDelete something you no longer need (a sub-user, a preset), then retry.
429rate_limitedToo many requests; wait for Retry-After secondsWait for Retry-After seconds, then retry. Spread your calls, or ask for bigger pages.
500internal_errorOur fault; retry, and tell support if it persistsRetry 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

LimitValue
Requests per key120 per minute
Purchases and balance codes per key10 per minute
Proxy checks per account1500 per 10 minutes, 100 per call
Requests with an invalid key, per address30 per minute
Proxy lines per call500

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.

Your API key is already in the dashboard.