# Authentication

> How API keys authenticate to MirAPI: bearer tokens, x-api-key, Gemini headers, key constraints, and the 401/403 distinction.

## Headers by protocol

Every protocol accepts your API key (`sk-...`) in its native form:

| Protocol | How the key is sent |
|---|---|
| OpenAI-compatible | `Authorization: Bearer sk-...` |
| Anthropic (`/v1/messages`) | `x-api-key: sk-...` |
| Anthropic | `Authorization: Bearer sk-...` also accepted |
| Gemini paths | `x-goog-api-key: sk-...` or `?key=sk-...` |

### Bearer details

- The `Bearer` scheme is case-insensitive: `Bearer`, `bearer`, and `BEARER` all work.
- A **bare key** is also accepted when no scheme is present (`Authorization: sk-...`).
- `GET /v1/models` and `/v1/messages` additionally accept `x-api-key`, which keeps Anthropic-style clients working without changes.
- `OpenAI-Organization` is accepted and **ignored** — there is no organization scoping.

## Key constraints

Keys are created and managed in the console at https://console.mirapi.ai. When you create a key, the full value is shown only once — store it in `MIRAPI_API_KEY` (or your secret manager) immediately. Four constraints can apply to a key:

| Constraint | Behavior |
|---|---|
| Model whitelist | Only whitelisted models are callable; others return 403 |
| Validity period | The key stops working after its end date |
| Quota limit | Requests are rejected once the key's spend cap is reached |
| IP allowlist | Only requests from allowed IPs are accepted |

## 401 vs 403

The two statuses mean different things and are not interchangeable:

- **401** — the key is missing, malformed, or unknown. Fix the credential.
- **403** — the key is valid and recognized, but the request was rejected: balance exhausted, model not in the key's whitelist, quota reached, IP not allowed, or another policy. Check the error message for the specific reason.

## Example

```bash
curl https://api.mirapi.ai/v1/chat/completions \
  -H "Authorization: Bearer $MIRAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "deepseek-chat", "messages": [{"role": "user", "content": "Hi"}]}'
```