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

# API errors

> The error envelope and the HTTP status codes.

Every non-2xx response uses the same envelope:

```json theme={null}
{
  "error": "Human-readable message",
  "error_code": "STABLE_CODE"
}
```

`error` is always present and written for a person to read. `error_code` is present on every refusal a route produces, and the HTTP status follows it. Four answers have no code, so branch on their status: `401`, the `403` for an account with no agent access, the `403` for a key without `read` permission, and the `429` for the request budget. A `500` also carries a `request_id`.

```json theme={null}
{
  "error": "Internal error",
  "error_code": "INTERNAL_ERROR",
  "request_id": "5b1e7c52-3f4a-4d0e-9a55-2d5cbe6f0a11"
}
```

For what each `error_code` means, see [Error codes](https://docs.allocait.app/api/error-codes.md).

## Status codes

| Status | Meaning |
| - | - |
| `400` | The request is malformed or breaks a rule it states: a missing field, a field of the wrong type, an id that isn't a UUID, a bad value, a missing or invalid price. |
| `401` | The API key is missing or invalid. |
| `403` | The key or the account stops the request: the key lacks the required permission, the account has no agent access, or an account limit was reached. The no-plan text is `This Allocait account has no active plan, so agent access is off. The user manages their account in the Allocait app.` Read `error_code` to tell an account limit (`TIER_LIMIT_EXCEEDED`, `FEATURE_NOT_AVAILABLE`) from a read-only key (`READ_ONLY_KEY`). |
| `404` | The path doesn't exist, or the portfolio, watchlist, input, scenario or other record it names doesn't exist or isn't yours. The two answer the same way, so the response doesn't say whether another account has that id. |
| `405` | The path exists but doesn't support the HTTP method used. The response carries an `Allow` header listing the supported methods and `error_code: INVALID_INPUT`. |
| `409` | The request is well formed but the stored state refuses it: a name already taken, a record still in use, a drop that needs confirming, not enough cash, or an `idempotency_key` reused with a different body. |
| `413` | The request body is larger than 1,000,000 bytes. It carries `error_code: INVALID_INPUT`. |
| `429` | A request budget or a per-route cap was exceeded. Three kinds: the per-minute budget (no `error_code`, `Retry-After: 60`), the daily budget (no `error_code`, `Retry-After` is the seconds until 00:00 UTC) and a per-route cap (`error_code: DAILY_LIMIT_EXCEEDED`, no `Retry-After`). See [Rate limits](https://docs.allocait.app/api/rate-limits.md). |
| `500` | An unexpected server error. The body is a fixed message with a `request_id`, not database detail. Retry a read once. Before you repeat a write, check the stored state, or repeat it only if it is safe to repeat (see [Idempotency](https://docs.allocait.app/api/idempotency.md)). Include the `request_id` when you contact [support](mailto:support@allocait.app). |

A mistake in the request should get a `400`, not a `500`. If a request you built gets a `500`, include its `request_id` when you report it. `POST /agent-feedback` takes a `request_id`.

## Next steps

* [Error codes](https://docs.allocait.app/api/error-codes.md): every code and its common causes.
* [Conventions](https://docs.allocait.app/api/conventions.md): ids, field types and body parsing.
* [Rate limits](https://docs.allocait.app/api/rate-limits.md): the `429` responses in detail.
* [Idempotency](https://docs.allocait.app/api/idempotency.md): retry a cash movement safely.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.