# Authentication

Every request carries one of your keys. You create keys in the console, send them in the `Authorization` header, and can give each one a spending limit.

## Create a key

Open [Keys](https://app.llm.buzz/console/keys) in the console and create a key. A key looks like `exp_vk_...`. The console shows the whole key once, when you create it, so copy it then and keep it in an environment variable or a secret store.

A key is one of two kinds:

| Kind | What it calls |
|---|---|
| Inference | The model API: Chat Completions, Responses, Messages and its `count_tokens`, Embeddings, Images, audio, the generation record (`/api/v1/generation`) and the model listings. |
| Management | Only the key routes: `/api/v1/key`, `/api/v1/credits` and `/api/v1/keys`. |

A key expires after 30, 90 or 365 days, or never, as you choose when you create it. On the Keys page you can disable a key and enable it again, or revoke it for good.

## Send the key

Send the key as a bearer token on every request:

```bash
curl https://api.llm.buzz/api/v1/models \
  -H "Authorization: Bearer $LLM_BUZZ_KEY"
```

The Messages API (`/api/v1/messages`) also takes the key in `x-api-key`, the header the Anthropic SDK sends. Point the Anthropic SDK at `https://api.llm.buzz/api`, without `/v1`: the SDK adds `/v1/messages` itself.

```python tab="Anthropic SDK"
from anthropic import Anthropic
import os

client = Anthropic(
    base_url="https://api.llm.buzz/api",
    api_key=os.environ["LLM_BUZZ_KEY"],
)
message = client.messages.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)
```

```bash tab="Claude Code"
export ANTHROPIC_BASE_URL="https://api.llm.buzz/api"
export ANTHROPIC_AUTH_TOKEN="$LLM_BUZZ_KEY"
export ANTHROPIC_MODEL="anthropic/claude-sonnet-5.5"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="anthropic/claude-haiku-5.5"
claude
```

Model names are matched exactly, and Claude Code's own default model names do not resolve on llm.buzz, so set every model it uses to a name from llm.buzz: `ANTHROPIC_MODEL` for the main model, and `ANTHROPIC_DEFAULT_HAIKU_MODEL` for the small model it runs background tasks on. If you switch models with `/model`, set `ANTHROPIC_DEFAULT_SONNET_MODEL` and `ANTHROPIC_DEFAULT_OPUS_MODEL` too. Any model on llm.buzz works there, Claude or not.

## Organizations

Keys, credit and logs belong to an organization. Signing up creates your own organization, and you can join others by invitation: an organization's owners and admins invite its members from the console, each with a role (owner, admin, billing or member). In an organization, each member has their own keys and logs, every member's requests draw on the organization's one prepaid balance, and its admins set its data policy and prompt logging on the Prompt logs page. The console's organization switcher picks the organization you work in.

## Check a key

`GET /api/v1/key` describes the key you send: its name, its limit, what is left of it and when it resets, its spend today, this week, this month and in total, and when it expires.

```bash
curl https://api.llm.buzz/api/v1/key \
  -H "Authorization: Bearer $LLM_BUZZ_KEY"
```

## Spending limits

An inference key can carry a limit in US dollars, per day, per week, per month or for the key's whole life. Days, weeks and months are UTC; a week starts on Monday. Set the limit when you create the key, or change it later on the Keys page. A management key can change it with `PATCH /api/v1/keys/{hash}`.

The limit is checked when a request arrives, against the key's spend in the current period. The request that crosses the limit completes, and the next one is refused with 403 `key_limit_exceeded`. Its `metadata.resets_at` says when the period ends, and is `null` for a lifetime limit. Model listings spend nothing and are never refused for the limit.

## When a key is refused

| Status | Code | What it means |
|---|---|---|
| 401 | `invalid_key` | The request has no key, or the key is unknown, expired, revoked or disabled. |
| 401 | `missing_authentication` | A key route was called without an `Authorization` header. |
| 403 | `key_limit_exceeded` | The key's spend in its period has reached its limit. Wait for `resets_at`, or raise the limit. |
| 403 | `management_key_not_allowed` | A management key called a model route. Use an inference key. |
| 403 | `management_key_required` | An inference key called `/api/v1/keys` or `/api/v1/credits`. Use a management key. |
