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

# API keys

> Creating, scoping, rotating and revoking.

Every request to `/v1` carries a key:

```bash theme={null}
curl https://api.voice.wixzel.com/v1/agents \
  -H "Authorization: Bearer $WIXZEL_API_KEY"
```

## Creating one

**Dashboard → API keys → Create key.** The secret appears once, at creation. We
store an HMAC of it rather than the key itself, so there is no endpoint that can
show it to you again and no support request that can recover it. A lost key is
replaced, not retrieved.

You can also create keys from the API, with a key that holds `api_keys:write` —
but the *first* key has to come from the dashboard, because there is nothing to
authenticate the request with yet.

## Scopes

Keys are scoped, and there is no wildcard. `agents:write` does not imply
`agents:read`; grant both if you need both.

| Group                  | Scopes                                                                                  |
| ---------------------- | --------------------------------------------------------------------------------------- |
| Agents                 | `agents:read` `agents:write`                                                            |
| Calls                  | `calls:read` `calls:write`                                                              |
| Telephony              | `sip_trunks:read` `sip_trunks:write` `phone_numbers:read` `phone_numbers:write`         |
| Contacts               | `leads:read` `leads:write` `campaigns:read` `campaigns:write`                           |
| Knowledge & scheduling | `knowledge_bases:read` `knowledge_bases:write` `appointments:read` `appointments:write` |
| Billing & usage        | `usage:read` `billing:read` `billing:write`                                             |
| Key management         | `api_keys:read` `api_keys:write`                                                        |

<Note>
  `webhooks:read` and `webhooks:write` appear in the API's scope list but are
  **reserved** — there are no webhook endpoints yet, so granting them does
  nothing.
</Note>

The quickstart needs `sip_trunks:write`, `phone_numbers:write`, `agents:read`,
`agents:write`, `calls:read`, `calls:write`, `usage:read` and `billing:read` —
which is exactly what the dashboard preselects.

<Warning>
  `billing:write` authorizes **spending money** — it is what creates a top-up
  checkout. Do not put it on a key that only needs to read a balance.
</Warning>

### There is no admin scope

One cannot be created either. Everything an administrator can do is unreachable
from an API key by construction, not by a permission check that could be
misconfigured — the credential is stripped before it reaches those routes.

### A key cannot grant what it does not hold

Creating a key with scopes the calling key lacks returns `403 scope_escalation`.
Otherwise a narrow key would be a step toward a broad one rather than a limit.

## Rotation

```bash theme={null}
curl -X POST https://api.voice.wixzel.com/v1/api-keys/{id}/rotate \
  -H "Authorization: Bearer $WIXZEL_API_KEY"
```

A replacement is issued immediately and **the old key keeps working for 24
hours**. That window exists so a deploy is never caught between two keys with
neither valid: ship the new one, let the old one expire.

## Revocation

```bash theme={null}
curl -X DELETE https://api.voice.wixzel.com/v1/api-keys/{id} \
  -H "Authorization: Bearer $WIXZEL_API_KEY"
```

Immediate, with no grace period. This is what you reach for when a key has
leaked — anything still using it starts failing at once.

## Storing them

Treat a key like a password. Environment variables or a secret manager; never a
repository, a client-side bundle, or a URL. Keys carry a `wv_live_` or
`wv_test_` prefix so a secret scanner can spot one, and so a test key pasted
into production fails loudly instead of quietly operating on real data.
