> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firetone.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors and limits

> Every error code, what it means, and whether to retry.

Every error has the same shape:

```json theme={null}
{ "error": { "code": "ip_not_allowed", "message": "this request came from 203.0.113.9, which this API key does not allow" } }
```

`code` is for your code, and `message` is for a person: it says what to fix.

## Codes

| Status | `code`                               | Meaning                                                               | Retry?                         |
| ------ | ------------------------------------ | --------------------------------------------------------------------- | ------------------------------ |
| 400    | `invalid_request`                    | The request is wrong; the message names the field                     | No: fix it                     |
| 401    | `unauthenticated`                    | No key, a mistyped key, or a revoked or expired key                   | No                             |
| 401    | `session_revoked`                    | A panel session from before a password change                         | Sign in again                  |
| 403    | `forbidden`                          | The key doesn't hold the permission, or the record isn't yours        | No                             |
| 403    | `ip_not_allowed`                     | The request came from an address the key doesn't allow                | Add the address to the key     |
| 403    | `ip_allowlist_required`              | An old key with no IP allowlist, past its grace                       | Add addresses to the key       |
| 403    | `console_destination`                | From the panel console: a real call to a number that isn't yours      | Use a dry run or a test number |
| 404    | `not_found`                          | No such record, or not one you can see (never "exists but forbidden") | No                             |
| 409    | `conflict`                           | Clashes with an existing record, for example a name or number         | No                             |
| 409    | `idempotency_mismatch`               | This `Idempotency-Key` was used with a different body                 | Use a new key                  |
| 409    | `idempotency_in_progress`            | The first request with this key is still running                      | Yes, shortly                   |
| 409    | `no_callback_secret`                 | A callback URL was given, but there's no secret to sign with          | Create the secret              |
| 409    | `wrong_status`                       | For example, pausing a campaign that isn't running                    | No                             |
| 409    | `not_registered`                     | The extension to ring has no phone signed in                          | When it does                   |
| 422    | `refused`                            | A call was checked and refused: no route, billing, or your own number | No                             |
| 422    | `not_ready`                          | A campaign can't start yet; the message says why                      | After fixing it                |
| 429    | `rate_limited`                       | Over the key's rate; wait `Retry-After` seconds                       | Yes, after the wait            |
| 502    | `originate_failed`, `provider_error` | The phone system or an AI provider refused                            | Maybe                          |
| 500    | `internal`                           | Our fault                                                             | Yes, with backoff              |

## Retrying safely

Retry `5xx`, `429` and `idempotency_in_progress` with backoff. Send an
`Idempotency-Key` on any `POST` that creates something or places a call, so a
retry after a timeout never does it twice. See
[Idempotency-Key](/api/authentication#retrying-safely-idempotency-key).

## Rate limits

* **Requests:** 600 a minute per key unless you set another rate on it.
* **Call placements:** at most 60 a minute, on `POST /calls` and
  `POST /calls/ai`.
* **Headers on every response:** `X-RateLimit-Limit`, `X-RateLimit-Remaining`
  and `X-RateLimit-Reset`.
* **Over the limit:** `429` with `Retry-After`.

## Sizes

| Limit                      | Value                            |
| -------------------------- | -------------------------------- |
| A request body             | 1 MB                             |
| A list page                | 50 by default, 500 at most       |
| Contacts per campaign load | 10,000                           |
| A CDR export               | 31 days                          |
| Variables on an AI call    | 30, of up to 500 characters each |

A field that isn't in the documented shape is refused, not ignored, so a typo
can't silently do nothing.
