> ## 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.

# Authentication

> API keys, permissions and scope.

Every request must carry an API key in the `x-api-key` header.

```bash theme={null}
curl https://allocait.app/api/v1/portfolios \
  -H "x-api-key: YOUR_API_KEY"
```

A request with a missing, malformed, expired or revoked key gets `401` with `{ "error": "Invalid or missing API key" }` and no `error_code`. The response says nothing more, so a wrong key and an expired key look alike. The [API quickstart](https://docs.allocait.app/api/quickstart.md) walks through a first call and its response.

## Create a key

In the Allocait app, open **Settings > API keys** and select **Create API key**. Enter a name (up to 100 characters), choose **Read only** or **Read and change**, and choose when the key expires: **Never**, **90 days** or **1 year**.

A new key starts with `alc_`. Allocait shows it once and stores only its SHA-256 hash, so it can't show the key again. If you lose a key, revoke it on the same page and create a new one. An account holds up to 20 keys; past that, creating one fails with `TIER_LIMIT_EXCEEDED`.

An API key authenticates the REST API and the MCP server. An app that connects to the MCP server with OAuth signs in through Allocait's consent page and doesn't use a key. See [Connect an agent](https://docs.allocait.app/connect-an-agent.md).

## Permissions

A key carries `read`, or `read` and `write`. In the app, you choose **Read only** or **Read and change** when you create it. A Core plan key is **Read only**. **Read and change** comes with Advanced.

* Every `GET` and every compute-only `POST` (`/compliance/check`, `/rebalance/preview`, `/portfolio/snapshot`, `/validate`, `/positions/size`, `/trades/check`, `/setup/preview`) needs `read`.
* Every route that writes data needs `write`.

A key without the right permission gets `403`:

| Missing | `error` | `error_code` |
| - | - | - |
| `read` | `This API key does not have read permission` | none. Branch on the status. |
| `write` | `Write permission required` | `READ_ONLY_KEY` |
| `write`, because the account's agent access is read-only | `This account's agent access is read-only.` | `READ_ONLY_KEY` |

One route reads the request body to decide which permission it needs: `POST /scenarios/{id}/rules` needs `read` when `dry_run` is `true` and `write` otherwise.

## Plan requirement

The API requires an active plan or trial.

* **Core** reads: every `GET` and every compute-only `POST`, including `/trades/check`. A write key issued on Advanced works read-only after a move to Core.
* **Advanced** reads and changes, and has webhooks.

An account with no active plan gets `403` with one fixed text, which names no plan. See [API errors](https://docs.allocait.app/api/errors.md#status-codes) for the text. Allocait reads the account's access level on every request, not only when you create a key, so a key follows the account's current access and not the access it had when you made the key.

## Scope

Every request is scoped to the key owner's own portfolios. Allocait takes the user from the key, not from the request, and passes that user to every route.

## Next steps

* [API quickstart](https://docs.allocait.app/api/quickstart.md): a key, a first read, a first check and error handling.
* [API errors](https://docs.allocait.app/api/errors.md): every refusal a key or an account can get.
* [Rate limits](https://docs.allocait.app/api/rate-limits.md): the request budget that every key shares.


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