# Authentication

One Authorization header. Routing keys authenticate inference; account tokens authenticate management.

*ProxyLLM docs · https://proxyllm.ai/docs/api/authentication*

Every request authenticates with the `Authorization` header:

```
Authorization: <token>
```

The `Bearer` prefix is optional; `Authorization: Bearer <token>` works exactly the same. The one endpoint that needs no token is [`GET /v1/models`](/docs/api/models).

## Which token where

| Token         | Prefix  | Authenticates                                                 | Create it under                                                            |
| ------------- | ------- | ------------------------------------------------------------- | -------------------------------------------------------------------------- |
| Routing key   | `pllm_` | Inference: `/v1/chat/completions`, `/v1/responses`, `/v1/key` | [Routing keys](https://proxyllm.ai/dashboard/routing-keys)                 |
| Account token | `sk_`   | Management, read and write: `/v1/organizations/…`             | [Settings → Account Tokens](https://proxyllm.ai/dashboard/settings/tokens) |
| Account token | `rk_`   | Management, read-only                                         | [Settings → Account Tokens](https://proxyllm.ai/dashboard/settings/tokens) |

## Routing keys

A routing key (`pllm_…`) is what your apps put in `OPENAI_API_KEY`. Each key carries its own routing plan and monthly budget, so you can hand a different key to each app or client and cap what it spends. Older `pk_…` keys keep working.

How lanes and budgets work: [Routing keys guide](/docs/routing-keys). To check what a key can do from code, call [`GET /v1/key`](/docs/api/key) with the key itself.

## Account tokens

An account token acts as you on the management endpoints under `/v1/organizations/`.

- `sk_…` reads and writes: create routing keys, register bridges, connect or disconnect Codex.
- `rk_…` is read-only: stats and lists. Hand these to agents, workflows, and service providers that only need to read. When an `rk_` token calls a write endpoint, the gateway refuses with `403 read_only_token`.

Legacy `pllm_live_…` tokens (minted before scopes existed) behave like `sk_`.

Tokens don't expire. Revoke one any time under [Settings → Account Tokens](https://proxyllm.ai/dashboard/settings/tokens). Treat them like passwords and keep them in server-side env vars.

An autonomous agent can obtain an `sk_` token without a human in the dashboard: [agent signup](/docs/api/agent-signup) verifies an email OTP and returns the token directly. Until a membership is activated, that token gets `402 payment_required` everywhere except [`GET /v1/organizations/me`](/docs/api/me).

## If you use the wrong one

The gateway names the mistake in the error message:

- An account token on an inference endpoint → `401 invalid_api_key`, with a message saying it's an account token and to use a routing key.
- A raw provider key (OpenAI `sk-…`) on an inference endpoint → `401 signup_required`, explaining a routing key is needed.
- A routing key on a management endpoint → `401 invalid_account_token`.

## Errors

| Status | Code                    | When                                                                         |
| ------ | ----------------------- | ---------------------------------------------------------------------------- |
| 401    | (none)                  | No token in the Authorization header, on a management endpoint.              |
| 401    | `signup_required`       | No token on an inference endpoint, or the token is a raw provider key.       |
| 401    | `invalid_api_key`       | The routing key doesn't exist or was revoked, or isn't a routing key at all. |
| 401    | `invalid_account_token` | The account token doesn't exist or was revoked, or isn't an account token.   |
| 403    | `read_only_token`       | A read-only (`rk_`) token called a write endpoint.                           |

The full table across all endpoints: [error codes](/docs/api#error-codes).
