Errors
One error shape for every endpoint, and how to react to each code.
When a request fails, the API answers with a non-2xx status and a JSON body:
{
"code": "not_found",
"message": "Service not found."
}codeis machine-readable and stable: switch on it.messageis written for humans and may be reworded at any time. Do not parse it.detailsis present on some endpoints whencodealone is not enough. Storage endpoints, for example, setdetails.codeto a finer reason such asbox_not_ready,snapshot_limitorconfirmation_required.
Codes
| Status | code | What to do |
|---|---|---|
| 400 | invalid_argument | The request is malformed or a value is out of range. Fix it; retrying will not help. |
| 400 | failed_precondition | The resource is not in a state that allows this (e.g. a server still building). |
| 401 | unauthenticated | Missing, unknown, revoked or expired token. |
| 403 | permission_denied | The token lacks the scope, or the account is suspended or restricted. |
| 404 | not_found | The resource does not exist or is not yours: we do not tell the two apart. |
| 409 | aborted | A conflicting operation is in progress (e.g. the server panel is busy), or an idempotency clash. |
| 429 | resource_exhausted | Rate limited. Back off and retry later. |
| 503 | unavailable | A panel or upstream could not be reached. Retry with backoff. |
| 500 | internal | Something broke on our side. Retry later; if it persists, open a ticket. |
Retrying safely
- Reads (
GET) can always be retried on 409, 429, 503 and 500 with exponential backoff. - Mutations answering 409 or 503 may have partly happened. Read the resource first, then decide whether to try again.
- Commercial operations are protected by an Idempotency-Key: never retry them with a new key without checking the invoice or order first.
- Credential-returning operations (password resets, console sessions) must not be repeated blindly: each call issues new credentials.
Something unclear or missing? Open a ticket and the team will get back to you.