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

# API keys and security

> Creating, scoping, rotating, and revoking BeatAPI keys, and where a key must never go.

# API keys and security

## Where do I create a key?

[Dashboard → API Keys](https://beatapi.io/dashboard/apikeys). Copy it when it is shown; it is not displayed again.

## How many keys should I have?

One per thing that calls BeatAPI — each application, each tool, each environment.

The cost is nothing and the benefits are immediate: `by_api_key` in `GET /v1/usage` attributes spend without any instrumentation, and a key that leaks or misbehaves can be revoked without taking down everything else.

Development, staging, and production should never share a key.

## Where must a key never go?

Anywhere a user or a stranger can read it:

* Browser JavaScript, or any client-side bundle. Anything shipped to a browser is public.
* Mobile applications. Decompilation is routine.
* A public repository, or a private one that may later be opened.
* Logs, error reports, screenshots, and support tickets.
* URL query strings — they are recorded by proxies, browser history, and server logs.

The header is the only correct place: `Authorization: Bearer <key>`.

## How do I keep a key out of my repository?

Use an environment variable and keep the file that sets it out of version control:

```bash
read -rsp "BeatAPI API key: " BEATAPI_API_KEY && echo
export BEATAPI_API_KEY
```

Reading it this way keeps it out of shell history too. Add `.env`, `~/.codex/auth.json`, and any tool config holding a key to `.gitignore`.

For the integrations that support it, prefer the environment-variable option over pasting the key into a config file. [Codex CLI](/integrations/codex-cli) supports `env_key` for exactly this reason.

## What if a key leaks?

Revoke it in [Dashboard → API Keys](https://beatapi.io/dashboard/apikeys) first, then create a replacement and update whatever used it. Revocation takes effect immediately.

Do it in that order. Rotating first and revoking later leaves a window in which the leaked key still spends your balance.

Afterwards, check `by_api_key` in `GET /v1/usage` for usage you do not recognise.

## How often should I rotate?

On a schedule you will actually keep, and immediately whenever someone with access leaves or a key may have been exposed. Per-component keys make rotation cheap, because each one touches a single deployment.

## Can a browser call BeatAPI directly?

Not with an API key. For the Realtime API, your server creates a Session and hands the browser a short-lived `client_secret` scoped to that Session — see [Realtime API](/realtime-api). Every other endpoint is server-side only.

Generated media is the exception, and only for reading: a task's artifact URL carries its own signed credential in the query string and grants access to that one object, so a browser can load it from an `<img>` or `<video>` with no header attached.

## Is my data used for training?

BeatAPI does not train on your requests. Review the [Privacy Policy](https://beatapi.io/privacy-policy) and [Terms of Service](https://beatapi.io/terms-of-service) before sending faces, voices, or other personal data, and before processing anything on someone else's behalf.

## How do I verify a webhook actually came from BeatAPI?

Verify the signature against the **raw request bytes**, before parsing JSON. Re-serialising the body changes it and the signature will not match. Check the timestamp too, so an old delivery cannot be replayed. See [Webhooks](/webhooks).

An unverified webhook endpoint is an unauthenticated write path into your system. Treat a failed verification as an attack, not as a bug.

## What is logged?

Requests are logged with a `request_id` for support and billing. Include that ID when reporting a problem — never the key itself.