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

# Authentication

> Authenticate PyAI requests with bearer API keys: pyai_test_ vs pyai_live_ environments, per-product scopes, WebSocket subprotocol auth, and key rotation.

Every request authenticates with a bearer API key.

```bash theme={null}
Authorization: Bearer pyai_live_...
```

`x-api-key: pyai_live_...` is an accepted alias for environments where setting an
`Authorization` header is awkward.

<Warning>
  Keys are opaque strings (up to 512 characters). **Never parse, split, or decode
  them.** They are self-validating and work on every PyAI surface the instant they
  are created, there is no activation or propagation delay.
</Warning>

## Environments

| Prefix       | Environment | Use it for                                                                                                |
| ------------ | ----------- | --------------------------------------------------------------------------------------------------------- |
| `pyai_test_` | Sandbox     | Evals, prototypes, CI. Works instantly against production models with hard daily caps and **no billing**. |
| `pyai_live_` | Production  | Real traffic, billed against your plan and credits.                                                       |

Create either in the [console](https://console.pyai.com). The key is shown once, store it as a secret (environment variable), never in source control.

## Scopes

Keys carry scopes that gate which products they can call:

| Scope              | Grants                                                                |
| ------------------ | --------------------------------------------------------------------- |
| `hear:transcribe`  | `POST /v1/audio/transcriptions`, transcription jobs (Hear)            |
| `hear:stream`      | streaming transcription / Cue (`GET /v1/audio/transcriptions/stream`) |
| `voice:synthesize` | `POST /v1/audio/speech` (Speak)                                       |
| `voice:clone`      | `/v1/voice/clones` (Speak)                                            |
| `omni:session`     | Omni realtime sessions (`/v1/omni`, `/v1/realtime`)                   |

`GET /v1/models` and `GET /v1/voices` are catalog reads, any active key may call
them. A request whose key lacks the required scope returns `403 forbidden`.

## WebSocket authentication

Browsers can't set headers on a WebSocket upgrade, so pass the key as a
subprotocol:

```
Sec-WebSocket-Protocol: pyai-key.pyai_live_...
```

Server-side clients may instead append `?api_key=...` to the URL. Never put the
key in any other query parameter.

## Rotation & revocation

Each key in the console has **rotate** and **revoke** controls.

* **Rotate** issues a new secret and invalidates the old one.
* **Revoke** disables the key everywhere within 60 seconds.

After revocation, calls with the old key return `401 unauthorized`.

<Tip>
  If a key is ever exposed, revoke it immediately and mint a new one, there is no
  penalty for rotating often.
</Tip>
