> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://statpad.dev/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://statpad.dev/docs/_mcp/server.

# API keys

> How to create a Statpad API key, send it over REST and the stream, keep it on your server, rotate it without downtime and revoke it.

Every REST request and stream connection needs an API key. Keys belong to your account, not to a person or an app: each one gets your plan and leagues, and every key on the account draws from the same [request allowance](/docs/get-started/rate-limits) and stream capacity. More keys never add capacity.

## Create a key

Sign in to [your account](https://app.statpad.dev), open **Keys** and choose **Create key**. Give the new key a name that says where it runs, such as `production-api` or `staging`, so you know which one to revoke later.

The full key is shown once, when you create it. Statpad stores only a hash and the key's prefix, which is what the Keys page lists. Copy the key into your secret manager or environment straight away. If you lose it, nobody can show it to you again: create a new key and revoke the old one.

Each plan has a key limit:

| Plan      | Active keys |
| --------- | ----------- |
| Pro trial | 2           |
| Developer | 2           |
| Pro       | 5           |
| Business  | 10          |

Revoked keys don't count toward it.

## Send it

Over REST, send the key in the `Authorization` header:

```bash
curl https://api.statpad.dev/v1/leagues \
  -H "Authorization: Bearer $STATPAD_API_KEY"
```

The stream at `wss://stream.statpad.dev/v1/stream` takes the same header. Browsers can't set headers on a WebSocket, so the stream also accepts the key as an `api_key` query parameter.

A missing, unknown or revoked key gets `401` with code [`unauthorized`](/docs/errors#unauthorized). A valid key whose account can't read what you asked for gets `403` with [`forbidden`](/docs/errors#forbidden).

## Keep keys on your server

Anyone who has a key can spend your allowance and hold your stream connections, and a key in a web page or a mobile app is readable by anyone who opens it. So call Statpad from your backend, and serve your own users from there:

* **Keep the key in your server's environment** or secret manager, never in front-end code or a repository.
* **Fan out from one connection.** One server-side stream subscription can feed any number of your users, while connections from every user's browser would use up your plan's connection limit.
* **Cache REST reads** on your side. Most responses carry an `ETag`, so a conditional request with `If-None-Match` answers `304` when nothing changed.

Use the `api_key` query parameter only where everyone who can load the page may hold the key, such as an internal dashboard. URLs end up in browser history and proxy logs.

## Rotate a key

Rotating replaces a key without downtime:

1. On the Keys page, choose **Rotate** on the key. Statpad creates a replacement with the same plan, leagues and limits. Rotating needs a free key slot.
2. Deploy the new key everywhere the old one runs.
3. Watch the old key's **Last used** time. It updates at most once a minute, so give it a few minutes after your deploy.
4. When it stops moving, revoke the old key.

Both keys work until you revoke the old one.

## Revoke a key

Revoking is immediate and can't be undone:

* The key's next REST request gets `401`.
* Stream connections opened with it close with `1008` within about five seconds.
* Your other keys and your allowance aren't affected.

If a key leaks, revoke it first and create its replacement second. A few seconds of `401`s cost less than someone else's traffic on your account.