Rate limits and errors
How the API answers when something is wrong, every error code it can return, and the rate limits that apply to your keys.
Response basics
Every answer, success or error, carries these headers:
| Header | Value |
|---|---|
Content-Type | application/json |
Cache-Control | no-store, private |
X-Request-Id | A 26-character id such as 01JCX7Q2M8ZK4T6V9B3N5R1W2Y. Quote it when you contact support. |
No answer sets a cookie. HEAD works on every GET endpoint and returns the same status and headers without a body.
The cacheable reads (/account, /offers, /offers/{id}, /servers, /servers/{id}, /servers/{id}/traffic, /orders, /orders/{id}, /invoices, /invoices/{id}, /ssh-keys) also carry X-Cache: hit or X-Cache: miss. A hit is served from a copy at most about a minute old; the body is the same as a miss.
The error body
{
"error": {
"code": "price_changed",
"message": "The total is not the expected_total that was sent. Nothing was ordered. The current total is in the details.",
"request_id": "01JCX7Q2M8ZK4T6V9B3N5R1W2Y",
"details": { "total": { "amount": "13900", "currency": "USD" } }
}
}
codeis stable. Write your code against it.messageis fixed text for the code. It never repeats anything you sent.detailsappears only when there is something you can act on. Its keys are listed below.401answers also carry the headerWWW-Authenticate: Bearer.405answers carryAllow, the methods the path takes.429 rate_limitedcarriesRetry-After, and so does any error whose details holdretry_after(in_progress,cooling_off).
Rate limits
| Limit | Default | Counted |
|---|---|---|
| Requests per key | 120 a minute | Every request made with the key. |
| Requests per account | 300 a minute | Every request from every key of the account. |
| Failed authentication | 30 a minute | Per IP address, never against your key: a stranger guessing keys cannot lock you out. |
There is also a short burst limit per IP address in front of the API.
Successful answers carry the tighter of the key and account counters:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window. |
X-RateLimit-Remaining | Requests left in it. |
X-RateLimit-Reset | When the window ends, in Unix seconds. |
Over a limit the answer is 429 rate_limited with a Retry-After header in seconds. Wait that long, then go on.
The window slides: what counts is roughly the last 60 seconds, so there is no burst at the turn of the minute. X-RateLimit-Reset is the end of the current clock minute.
Writes have their own ceilings (power actions per hour, reverse DNS requests per day, SSH key changes per day, order limits). Those answer 429 action_limit or 403 cap_reached, described on their pages.
Error codes
| Status | Code | Message | When |
|---|---|---|---|
| 400 | body_not_allowed | This request must not have a body. | A GET, HEAD or DELETE was sent with a body. |
| 400 | key_in_url | API keys are accepted only in the Authorization header. A working key sent in a URL is revoked. | A key appeared in the address. Every working key there is revoked and the owner emailed. |
| 400 | invalid_parameter | A query parameter is not allowed here or its value is not valid. See the API documentation for this endpoint. | An unknown, repeated, empty or malformed query parameter. |
| 400 | invalid_body | The request body is not valid JSON of the documented shape for this endpoint. Unknown fields are refused. | Body missing, not application/json, over 4 KB, not one JSON object, a duplicate or unknown field, or a field of the wrong shape. |
| 400 | idempotency_key_required | This request needs an Idempotency-Key header of 8 to 64 letters, digits, dashes or underscores. | A write without a valid Idempotency-Key. |
| 401 | invalid_key | Missing or invalid API key. Send it as "Authorization: Bearer <key>". | No key, a malformed key, or a key we do not know. |
| 401 | key_revoked | This API key has been revoked. | See When a key stops working. |
| 401 | key_expired | This API key has expired. | The key passed its expiry date. |
| 401 | test_key | Test keys cannot be used on the live API. | A rsw_test_ key. |
| 402 | insufficient_credit | The account credit that may be spent through the API does not cover this order. Add funds in the client area. | details.needed is the amount missing. |
| 403 | api_not_enabled | API access is not enabled for this account. | The owner has not turned API access on. |
| 403 | account_blocked | API access for this account is blocked. Please contact support. | Blocked by RedSwitches. |
| 403 | not_invited | API access is by invitation only for now. | The account is not in the beta. |
| 403 | ip_not_allowed | This key cannot be used from your IP address. | The key's IP list does not include your address. |
| 403 | account_inactive | This account is not active. | The account is not active. |
| 403 | owner_changed | This API key was created by a user who no longer owns the account. The owner must create a new key. | The account has a new owner. |
| 403 | email_not_verified | The account owner must verify their email address before the API can be used. | Owner email not verified. |
| 403 | permission_denied | This API key does not have the permission this endpoint needs. | Missing permission, or a power request for a server not on the key's list. |
| 403 | ordering_not_enabled | Ordering through the API is not turned on for this account. The owner turns it on on the API page. | See the Ordering guide. |
| 403 | not_eligible | This account cannot order through the API right now. The account owner can see the reason on the API page. | The account may not order now. |
| 403 | cooling_off | Ordering opens 24 hours after it was turned on and after a new ordering key. | details.retry_after says how many seconds are left. |
| 403 | cap_reached | This order would go over a limit of this key or of the account. Nothing was ordered. | details.cap names the limit, details.limit its value and details.window its window. Account limits are set by RedSwitches: contact support to raise one. |
| 403 | ordering_paused | Ordering through the API is paused by RedSwitches. Nothing was ordered. Try again later. | Ordering is paused for everyone. |
| 403 | power_paused | Power actions through the API are paused for this account. RedSwitches staff have been told. | Too many power-offs in a short time. See Power and actions. |
| 404 | not_found | Nothing was found at this address: no such endpoint, or no such item on this account. | No such endpoint, a malformed id, or an item that does not exist or is not yours. |
| 405 | method_not_allowed | This endpoint does not take this method. The Allow header lists the methods it takes. | The method is not allowed on this path. GET /actions/{id}/credentials also refuses HEAD. |
| 413 | body_too_large | The request body is larger than 16 KB. | Refused before the API reads it. |
| 409 | in_progress | A request with this Idempotency-Key is still being processed. Ask again with the same key in a few seconds. | details.retry_after and the Retry-After header, in seconds. |
| 409 | price_changed | The total is not the expected_total that was sent. Nothing was ordered. The current total is in the details. | details.total is the current total. |
| 409 | sold_out | This server is not in stock any more. Nothing was ordered. | Pick another offer. |
| 409 | order_not_placed | The order could not be completed and nothing was charged. RedSwitches staff have been told. | Nothing was created. |
| 409 | order_under_review | This order needs a check by RedSwitches staff before it continues. Do not repeat it; you will hear from us. | details.order is the order id when there is one. |
| 409 | server_busy | Another action on this server is queued, running or unsettled. Wait until it has finished, then try again. | Also while the server is being delivered or installed. |
| 409 | server_not_active | This server is not active (pending, suspended or ended), so this action is not available. | |
| 409 | ssh_key_conflict | That key is already saved on this account, or the account holds the most keys it can. | |
| 422 | not_supported | This server does not support that through the API. | |
| 422 | ip_not_on_server | That IP address is not assigned to this server. | |
| 422 | invalid_ssh_key | That is not a valid SSH public key. | |
| 422 | idempotency_conflict | This Idempotency-Key was used for a different request. Use a new key for a new order. | Same key, different body or server. |
| 422 | not_orderable | This offer cannot be ordered with these choices through the API. | Offer, OS, SSH key or billing cycle not allowed. |
| 429 | action_limit | This would go over a limit of the account for this action (see the details). Nothing was changed. Try again later. | details.limit and details.per. |
| 429 | rate_limited | Too many requests. Wait for the number of seconds in the Retry-After header. | See Rate limits above. |
| 500 | internal_error | Something went wrong on our side. Quote the request id when you contact support. | |
| 503 | unavailable | The API is temporarily unavailable. | Maintenance, a part of the API switched off, or a dependency down. Retry later. |
A 404 looks exactly the same whether the item does not exist or belongs to another account.
Details keys
| Key | Appears with | Shape |
|---|---|---|
total | price_changed | {"amount": "13900", "currency": "USD"}: the current first-payment total in minor units. |
needed | insufficient_credit | {"amount": "2500", "currency": "USD"}: credit missing, in minor units. |
cap | cap_reached | servers_day, servers_month, open, money_month, renewal_month or key_month. |
order | order_under_review | The order id, such as "ord_456". |
retry_after | in_progress, cooling_off | Seconds to wait. |
limit | action_limit, cap_reached | action_limit: the ceiling, as a number. cap_reached: the limit in force: a number for servers_day, servers_month and open; an amount such as {"amount": "200000", "currency": "EUR"} (minor units, the account's currency) for money_month, renewal_month and key_month. |
window | cap_reached | day (servers_day), 30_days (servers_month, money_month, renewal_month, key_month) or open (paid orders not delivered yet; no time window). |
per | action_limit | server_hour, account_hour, server_day or account_day. |
field | invalid_body | The documented field that failed, such as "label" or "hostname". Absent when the failure is not about one field. |
reason | invalid_body | What is accepted, in fixed words, such as "one of on, off, reboot". Your value is never echoed back. |
With details.reason, the invalid_body message names the problem too: The request body is not valid: action: one of on, off, reboot.
Requests the API refuses before it looks at them
- Query parameters exist only where an endpoint lists them (
cursorandlimiton lists,dry_run=trueon orders). Anything else is400 invalid_parameter. GET,HEADandDELETEmust not have a body:400 body_not_allowed.POSTbodies are one JSON object,Content-Type: application/json, at most 4 KB. Unknown fields and names given twice are refused:400 invalid_body. A body over 16 KB is413 body_too_large.- Ids in paths must have the right prefix for the endpoint (
srv_on/servers/{id}). A wrong prefix, a leading zero or anything encoded is404 not_found.