# Errors

Every error has the same envelope, and every code has a page that explains it and how to fix it.

## The envelope

The body of every 4xx and 5xx response.

```json
{
  "error": {
    "code": "invalid_hostname",
    "message": "That is not a valid hostname.",
    "fix": "Send a hostname like careers.acme.com: no scheme, path, port, wildcard or IP address.",
    "docs": "https://apexly.dev/docs/errors/invalid_hostname"
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `error.code` | `string` | Stable, machine-readable; branch on this. |
| `error.message` | `string` | What went wrong, in plain words. |
| `error.fix` | `string` | What to do about it, in one sentence. |
| `error.docs` | `string` | The page for this code, e.g. https://apexly.dev/docs/errors/invalid_hostname. |
| `error.request_id` | `string` | internal_error only: quote it when you contact support. |

## Codes

Each code links to its page: what it means, why it happens and what to do.

| Code | HTTP | Message |
| --- | --- | --- |
| [`invalid_request`](/docs/errors/invalid_request) | 400 | The request could not be read. |
| [`unauthorized`](/docs/errors/unauthorized) | 401 | The API key is missing, invalid or revoked. |
| [`forbidden`](/docs/errors/forbidden) | 403 | This credential is not allowed to do that. |
| [`card_required`](/docs/errors/card_required) | 402 | Live keys need a card on file. |
| [`live_keys_need_plan`](/docs/errors/live_keys_need_plan) | 402 | Live keys need a plan: this account is on Free. |
| [`card_declined`](/docs/errors/card_declined) | 402 | The card was declined. |
| [`account_suspended`](/docs/errors/account_suspended) | 403 | The account is suspended, so changes are paused. Existing domains keep serving. |
| [`plan_required`](/docs/errors/plan_required) | 403 | This feature is not included in the current plan. |
| [`not_found`](/docs/errors/not_found) | 404 | Nothing exists at this path, or it belongs to another app. |
| [`idempotency_key_in_use`](/docs/errors/idempotency_key_in_use) | 409 | A request with this Idempotency-Key is still being processed. |
| [`payload_too_large`](/docs/errors/payload_too_large) | 413 | The request body is larger than 100 KB. |
| [`validation_failed`](/docs/errors/validation_failed) | 422 | The request did not pass validation. |
| [`idempotency_key_reused`](/docs/errors/idempotency_key_reused) | 422 | This Idempotency-Key was already used with a different request. |
| [`invalid_hostname`](/docs/errors/invalid_hostname) | 422 | That is not a valid hostname. |
| [`hostname_is_apexly`](/docs/errors/hostname_is_apexly) | 422 | Hostnames under Apexly zones cannot be added. |
| [`hostname_is_public_suffix`](/docs/errors/hostname_is_public_suffix) | 422 | That hostname is a public suffix, so nobody can prove control of it. |
| [`hostname_held`](/docs/errors/hostname_held) | 422 | This hostname is held for review. |
| [`domain_limit_reached`](/docs/errors/domain_limit_reached) | 422 | The plan does not allow more domains. |
| [`origin_not_allowed`](/docs/errors/origin_not_allowed) | 422 | That origin cannot be used. |
| [`rate_limited`](/docs/errors/rate_limited) | 429 | Too many requests. |
| [`billing_unavailable`](/docs/errors/billing_unavailable) | 503 | The billing provider did not answer. |
| [`internal_error`](/docs/errors/internal_error) | 500 | Something went wrong on our side. |
