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

# Authentication

> The two ways to authenticate to the Atlaso Build API, the exact headers and key formats, and every error code.

All Build API calls go to `https://mcp.atlaso.ai/developer/v1` and authenticate
in one of two ways.

## Mode A — project key + subject

The primary, server-to-server model. You send your project key and name the
end-user you're acting for:

```http theme={null}
X-Atlaso-Project-Key: atlk_<prefix>_<secret>
X-Atlaso-Subject:     <your end-user id>
```

* **Key format:** `atlk_` + a 12-character hex prefix + `_` + a long random
  secret. Mint it in **Settings → Developer → New key**; it's shown once.
* **Subject:** any stable string you choose for one of your users or devices.
  Must match `^[A-Za-z0-9_.:@\-]{1,128}$`. It's **case-sensitive** and stored
  as-is.

The project key can address **any** subject in the project — so it must stay on
your server (see [below](#keeping-keys-safe)).

## Mode B — per-device credential

For hardware you don't fully control (an ESP32, a robot), mint a credential
whose subject is baked in, so the device can't address anyone else:

```http theme={null}
Authorization: Bearer atldev_<id>_<secret>
```

* **Format:** `atldev_` + a 12-character hex id + `_` + a 32-character hex
  secret (128-bit).
* The subject is **pinned** to the credential. Sending an `X-Atlaso-Subject`
  header alongside a device bearer is rejected with `400` — the credential
  already decides the subject.
* A device credential can only `remember`, `recall`, and delete its own
  subject's memories. It can never mint other credentials or create projects.

Mint, batch-enroll, and revoke device credentials from your backend — see
[Devices & hardware](/build/devices).

## Keeping keys safe

<Warning>
  A project key (`atlk_…`) is a bearer secret. Anyone holding it can read and
  write **every** subject in the project. Keep it server-side — never ship it in
  a browser bundle, a mobile app, or on device flash. For devices, use a
  per-device `atldev_` credential instead.
</Warning>

The `X-Atlaso-Subject` header is a **claim, not a login** — Atlaso trusts that
your server already authenticated the end-user before it set the subject. Do
your own auth first, then call Atlaso.

## Errors

Failures are fail-closed and return JSON. Authentication and entitlement
failures include an `X-Atlaso-Error` header naming the cause; some validation
`400` and `422` responses use FastAPI's standard error shape and omit that
header.

| Status | Meaning                                                                                                                      |
| ------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Missing or invalid subject; empty or oversized text, tags, or recall query. Some validation responses omit `X-Atlaso-Error`. |
| `401`  | Missing / malformed / unknown project key, or an invalid device credential.                                                  |
| `402`  | The account's Build subscription isn't active. Existing keys stop serving until it's renewed — nothing is deleted.           |
| `403`  | The project is inactive, the action isn't allowed for this credential, or a device tried to touch another subject.           |
| `409`  | Idempotency conflict — same `Idempotency-Key`, different body — or a device-credential cap was reached.                      |
| `413`  | Storage quota exceeded (see [Limits](/build/limits#storage)).                                                                |
| `422`  | Missing or mistyped parameters, or memory-gate rejection (`gate_rejected`).                                                  |
| `429`  | Rate limited. Data-plane responses include `Retry-After`; provisioning responses may omit it.                                |
| `503`  | Server temporarily can't place the request (`placement_denied`), or the tier isn't configured. Retry with backoff.           |

<Note>
  A lapsed Build subscription returns `402` on the data plane but **keeps your
  keys and memories intact**, and you can still list and revoke keys — so you
  can wind down or kill a leaked key even while unsubscribed. Renew and
  everything resumes.
</Note>
