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

# Authentication

> Create an account, get a Bearer API key, and manage keys from your Dahl account.

Dahl inference uses a **Bearer API key** on every `POST /v1/chat/completions` request. Keys are free and each includes **100 million tokens**. There is no payment UI yet — create another key when a key's allowance is spent.

You can get a key two ways:

1. **Recommended — create an account** (username + fingerprint), then manage keys at [inference.dahl.global/account](https://inference.dahl.global/account).
2. **Quick — anonymous key** from the landing page or `POST /tokens` (same 100M allowance; you can link it to an account later).

The account session (cookie) is only for the account UI. Inference always uses `Authorization: Bearer <api_key>`.

## Create an account

1. Open [inference.dahl.global](https://inference.dahl.global) and click **Create account** (or go to [/account](https://inference.dahl.global/account)).
2. Pick a username: **3–20 characters**, letters, digits, underscore.
3. Save the **fingerprint** you are shown once — it is your password. We store only a hash; fingerprints **cannot be recovered**.
4. Your first API key is issued immediately. Copy it into your password manager.

### Sign in again

Sign-in needs only the fingerprint (not the username):

```bash theme={null}
curl -X POST https://inference.dahl.global/v1/auth/signin \
  -H "Content-Type: application/json" \
  -d '{"fingerprint":"your-32-char-fingerprint"}' \
  -c cookies.txt
```

Or use **Sign in** on the site and paste the fingerprint. Session cookies last 30 days.

<Warning>
  If you lose the fingerprint, create a new account. There is no email recovery by design.
</Warning>

### Signup via API

```bash theme={null}
curl -X POST https://inference.dahl.global/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"username":"swift_eagle_449"}'
```

Example response:

```json theme={null}
{
  "user": { "user_id": "…", "username": "swift_eagle_449", "created_at": "…" },
  "fingerprint": "a1b2c3d4e5f6…",
  "api_key": {
    "id": 123,
    "token": "dahl_…",
    "available_tokens": 100000000
  }
}
```

Check username availability first with `GET /v1/auth/check-username?username=…`.

## Manage keys in your account

At [inference.dahl.global/account](https://inference.dahl.global/account) (or with a session cookie):

| Action                | Endpoint                                                   |
| --------------------- | ---------------------------------------------------------- |
| List keys             | `GET /v1/account/keys`                                     |
| Create a key          | `POST /v1/account/keys`                                    |
| Revoke a key          | `DELETE /v1/account/keys/{id}`                             |
| Link an anonymous key | `POST /v1/account/keys/claim` with `{ "token": "dahl_…" }` |
| Usage summary         | `GET /v1/account/usage?days=30`                            |
| Sign out              | `POST /v1/auth/signout`                                    |

Each new key again includes **100 million tokens**. Statuses: `active`, `exhausted`, `revoked`.

```bash theme={null}
curl -X POST https://inference.dahl.global/v1/account/keys \
  -b cookies.txt
```

## Anonymous key (no account)

Still supported for a fast start — the landing page **Get API key** / scratch flow and `POST /tokens` create an unattached key:

```bash theme={null}
curl -X POST https://inference.dahl.global/tokens
```

```json theme={null}
{
  "token": "dahl_…",
  "available_tokens": 100000000
}
```

You can later **claim** that key into an account from the account page so balances and usage live under one profile.

<Note>
  Token issue endpoints live at the service root (`/tokens`) or under `/v1/auth` and `/v1/account`. Chat completions use `https://inference.dahl.global/v1/...`.
</Note>

## Check remaining balance

With any API key, call `GET /tokens/current`:

```bash theme={null}
curl https://inference.dahl.global/tokens/current \
  -H "Authorization: Bearer $DAHL_API_KEY"
```

```json theme={null}
{
  "available_tokens": 99823456
}
```

Successful inference deducts **input + output** tokens from the upstream `usage` field when present. The [chat UI](https://inference.dahl.global/chat) and account page refresh the same balance.

## Use the key on requests

```bash theme={null}
curl https://inference.dahl.global/v1/chat/completions \
  -H "Authorization: Bearer $DAHL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"MiniMaxAI/MiniMax-M2.7","messages":[{"role":"user","content":"Hi"}]}'
```

The header must be exactly two words: `Bearer` followed by the token. Other formats are treated as missing auth.

## Public endpoints

These do **not** require a token:

* `GET /v1/models` — list model IDs
* `GET /v1/status` — recent model uptime probes
* `GET /health` — service health
* `GET /v1/auth/check-username` — username availability

## Error responses

Missing or invalid keys return **401**:

```json theme={null}
{
  "error": {
    "message": "Missing API token"
  }
}
```

Other messages you may see: `invalid API token`, `expired API token`, `not signed in`, `session expired`, `invalid fingerprint`.

When the key has no allowance left, protected inference routes return **402 Payment Required**:

```json theme={null}
{
  "error": {
    "message": "available tokens exhausted"
  }
}
```

Create a new key (account page or `POST /tokens`) when the allowance is spent. Signup / sign-in rate limits return **429** (`too many signup attempts` / `too many sign-in attempts`).

## Security practices

* Treat the **fingerprint** like a password — save it once, never commit it
* Do not commit API keys to source control — use environment variables or a secrets manager
* Revoke keys from the account page if they may have been exposed
* Prefer one account with separate keys per environment (development, staging, production)
