# Authentication & API keys

Every programmatic request to the Bird API authenticates with an API key passed as a bearer token. Keys belong to a workspace, carry a fixed set of permissions chosen at creation, and are shown in full exactly once. (The dashboard itself signs in with a session cookie; everything you build authenticates with a key.)

## How requests authenticate

Pass your key in the `Authorization` header on every request:

```bash
curl -X POST https://us1.platform.bird.com/v1/email/messages \
  -H "Authorization: Bearer $BIRD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from": "hello@yourdomain.com", "to": ["delivered@messagebird.dev"], "subject": "Hi", "text": "Hello." }'
```

The region in the key prefix tells you which host to call: `bk_us1_...` keys go to `https://us1.platform.bird.com`, `bk_eu1_...` keys to `https://eu1.platform.bird.com`. Official Bird SDKs and the CLI read the region from the key and select the host for you. A key sent to the wrong regional host returns `421` (type `misdirected_error`); see [Regions](/docs/api/regions).

A missing or invalid key returns `401`. A valid key that lacks the permission an endpoint requires returns `403`. Header semantics and error responses live in the [authentication reference](/docs/api/authentication).

## Anatomy of a key

```text
bk_us1_Ab3xKq9mP2wR5tY8uI1oL4nJ2kQ9m
└┬┘└┬┘ └──────────┬──────────┘└─┬──┘
 │  │          payload      checksum
 │  └ region (routes the request)
 └ Bird key prefix
```

- **Prefix**: `bk_{region}_` names the credential type and its region. The fixed, distinctive prefix is what lets secret scanners recognize a Bird key in code, and the region segment routes your request to the right host.
- **Payload**: 23 random characters carrying 136 bits of entropy.
- **Checksum**: the last 6 characters are a checksum of the rest of the key, so an SDK or the API can reject a mistyped or truncated key immediately, before it is ever looked up.

The full key is returned **once**, in the response that creates it. Bird stores only a keyed hash (HMAC-SHA-256); the plaintext cannot be retrieved again, by you or by Bird. What you can see afterwards is the `key_prefix` (the first 15 characters, e.g. `bk_us1_Ab3xKq9m`) and a stable 12-character `fingerprint` for matching a key in logs and support conversations without exposing its value.

If you lose a key, you don't recover it: you [revoke it](#revoking-a-key) and create a new one.

## Creating a key

Create keys in the dashboard under [**Developers → API keys**](https://bird.com/dashboard/w/api-keys). A key is created with a name, one or more scopes, and an optional expiry. The response that creates it is the only one that ever carries the `token` field (the full key): store it in your secret manager immediately.

![The API Keys page in the Bird dashboard, listing keys with their masked prefix, scopes, and last-used time](/images/docs/dashboard-api-keys.png)

Three properties are fixed the moment the key exists:

- **The scope set is immutable.** Scopes cannot be added or removed on an existing key. To change what a key can do, create a new key with the right scopes and revoke the old one; every key's permissions stay exactly what they were when it was issued and audited.
- **Expiry is immutable too.** Set `expires_at` when a key should stop working at a known time (a contractor's engagement, a migration window). Past that moment the key returns `401`; a key without an expiry lives until revoked.
- **Key management stays with people.** Creating and revoking keys requires the `api_keys:write` permission, held by the workspace admin and developer roles (see [Users, teams & roles](/docs/guides/users-teams-roles)) and never grantable to an API key itself. A leaked key cannot mint more keys.

The API keys page lists every key with its `key_prefix`, scopes, and `last_used_on` date (day precision), so you can spot stale keys at a glance. Revoked keys stay out of the listing unless you choose to show them.

## Scopes & levels

Each scope on a key is a `{scope, level}` pair, where `level` is `read` or `write` (`write` includes `read`). API keys hold data-plane scopes:

| Scope                 | `read`                                     | `write`                                     |
| --------------------- | ------------------------------------------ | ------------------------------------------- |
| `emails`              | Read sent messages and delivery status     | Send email                                  |
| `email_management`    | Read suppressions and email configuration  | Manage suppressions and email configuration |
| `email_marketing`     | Read contacts, audiences, and broadcasts   | Manage contacts, audiences, and broadcasts  |
| `domains`             | Read sending domains and their DNS records | Add, verify, and manage sending domains     |
| `sms`                 | Read sent SMS and delivery status          | Send SMS                                    |
| `whatsapp_messages`   | Read sent WhatsApp messages and status     | Send WhatsApp messages                      |
| `whatsapp_management` | Read WhatsApp templates and settings       | Manage WhatsApp templates and settings      |
| `verify`              | Read verification status                   | Send and check verification codes           |

Control-plane operations (workspace members, settings, key issuance, IP pools) are deliberately not grantable to API keys; they remain dashboard-only. More scopes will be added as products gain programmatic surfaces. Grant the narrowest set that works: a key that only sends email should hold `emails:write` and nothing else.

## Revoking a key

Revoke a key from its row on the [**Developers → API keys**](https://bird.com/dashboard/w/api-keys) page. Revocation is permanent: a revoked key cannot be reactivated, and its record is preserved for audit with `revoked_at` set.

Revocation propagates fast but not instantly. Key validation runs through a short-lived cache, so a freshly revoked key can keep working for a few seconds (five at most) before every request with it returns `401`.

Bird has no rotate operation. To rotate a key with zero downtime, overlap two keys:

1. Create a new key with the same scopes.
2. Deploy the new key to your services.
3. Watch the old key's `last_used_on` until traffic has moved.
4. Revoke the old key.

## Keys belong to the workspace

An API key is bound to exactly one workspace: it authenticates as the workspace, not as the person who created it. That has two practical consequences:

- **Keys survive departures.** When an employee leaves and their user account is removed, the keys they created keep working. You never have a production outage because the person who clicked "create" left the company. (Their departure is still a good prompt to rotate keys they had access to.)
- **One workspace per key.** A key cannot reach resources in another workspace, and it can never perform organization-level operations (billing, org members, org settings). If you operate multiple workspaces, create a key in each.

Because the key pins the workspace, requests with a key need no context headers; see [Workspaces](/docs/guides/workspaces) for how context resolution works across credential types.

## The delegated path: OAuth tokens for the CLI and MCP server

API keys are for services. When a _person_ uses the [Bird CLI](/docs/ai/cli-for-agents) or the [Bird MCP server](/docs/ai/mcp-server), those tools authenticate via OAuth instead: you log in as yourself in the browser, choose a workspace and a subset of your own permissions, and the tool receives a short-lived `bt_{region}_...` user token. These tokens are capped to what you personally hold and revocable per tool under [**Profile → Connected apps**](https://bird.com/dashboard/profile/connected-apps). They are never something you copy-paste or store in a secret manager; don't use them in place of API keys for server workloads.

## Next steps

- [Authentication reference](/docs/api/authentication): request header semantics and error responses
- [Regions](/docs/api/regions): regional hosts and routing
- [Users, teams & roles](/docs/guides/users-teams-roles): who can manage keys
- [Workspaces](/docs/guides/workspaces): the workspace a key binds to