# Authentication and API keys

> Authenticate REST API calls with an organization API key, limit what each key can do and which agents it can reach, and manage keys in the dashboard or through the API.

Source: https://docs.runbear.io/api/api-keys

Last updated: 2026-10-07

Every REST API request authenticates as your organization with an **API key**,
sent as a bearer token. A key can carry a scope: which kinds of changes it may
make, and which agents it may touch. Give each system its own key, scoped to
what that system needs, so a leaked key can do as little as possible.

```http
Authorization: Bearer <your API key>
```

The one exception is the [Web SDK](/api/web-sdk/authentication.md), which runs in a
browser and uses a short-lived session pass that your server mints with an API
key.

> **Warning**
>
> An API key is an organization-level credential. Anyone holding it can act as your
> organization within the key's scope. Never ship one in browser JavaScript, a
> mobile app, or a public repository. To put an agent in a web page, use the
> [Web SDK's session passes](/api/web-sdk/authentication.md#session-mode), which keep the key on your
> server.

## Creating a key

> **Paid plans only**
>
> The API isn't available during the 14-day Team free trial. While your
> organization is trialing, you can't create API keys, and requests to the API are
> refused with `403` `api_access_unavailable_during_trial`. API access starts
> when the trial ends and your paid subscription starts; changing plans during the
> trial doesn't end it early. Existing keys then work without being regenerated.

Open **Settings → API keys** (where available) and select **Create API key**.
If your organization doesn't show that item, open **Settings → Members**, which
opens your organization's account page, and manage keys in its **API Keys**
section.

On **Settings → API keys**:

1. Enter a **Description** that names the system that will use the key, such as
   `Acme Corp integration`, so an unfamiliar key in a log can be traced back to
   its owner.
2. Choose the key's capabilities and, if it should reach only some agents, fill
   in the **Agent allowlist**. Both are explained below.
3. Select **Create key**. The key is shown once. Copy it into your secret
   manager before you close the dialog.

The capability switches and the agent allowlist are edited only on
**Settings → API keys**, or through the [API](#managing-keys-through-the-api)
with a key that holds `manageApiKeys`. A key created on the organization's
account page carries no scope, and behaves like a
[key created before scopes](#keys-without-a-scope).

## Capabilities

A capability allows a kind of **change**. Reads need only a valid key, with one
exception: listing API keys requires `manageApiKeys`.

| Capability      | Dashboard label      | Allows                                                                                                                                 | Default |
| --------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `chat`          | **Chat with agents** | Creating threads, running turns, chat completions and suggestions, file uploads, and minting Web SDK session passes                    | On      |
| `manageAgents`  | **Edit agents**      | Creating, updating and deleting agents and their knowledge, tools and hooks, and changing organization settings such as the AI Gateway | On      |
| `manageApiKeys` | **Manage API keys**  | Listing, creating, editing and revoking the organization's API keys                                                                    | Off     |

`manageApiKeys` is effectively full admin access: a key that can create keys can
create one with every capability. Keep it for internal automation and never hand
it to a client.

A change whose operation declares no capability requires `manageAgents`.

## Agent allowlist

An empty allowlist means the key can reach every agent in the organization,
including agents created later. A key with an allowlist is limited to the agents
on it:

- A request that addresses an agent outside the list, by path, body or query, or
  through a thread that belongs to one, is refused with `403`
  `forbidden_by_agent_allowlist`. That includes
  `GET /v1/threads?assistant_id=` for such an agent.
- Two list endpoints filter instead of refusing: `GET /v1/assistants` and
  `GET /v1/agents?ids=` silently leave out agents outside the list.
- Organization settings are off limits. The credits, API keys, AI Gateway,
  Google Drive service accounts and integration suggestions endpoints answer
  `403` `forbidden_org_endpoint_for_scoped_key`, reads included.

## How a request is checked

Each request passes three gates in order, and the first one that fails decides
the `403`:

1. **Capability** (changes only): does the key hold the capability the
   operation requires? Otherwise `forbidden_by_key_role`.
2. **Organization settings:** is this an organization-level endpoint and the key
   limited to an allowlist? Then `forbidden_org_endpoint_for_scoped_key`.
3. **Allowlist:** is the addressed agent outside the key's list? Then
   `forbidden_by_agent_allowlist`.

Every operation falls into one of three classes: **agent-scoped** (it addresses
an agent, so the allowlist applies), **org-config** (organization settings,
refused for allowlisted keys) and **catalog** (organization-independent data;
neither gate applies). The [OpenAPI document](https://api.runbear.io/v1/docs)
publishes each operation's class and required capability as the
`x-runbear-scope` extension, and describes the vocabulary once at its root
under `x-runbear-api-key-scopes`.

### Keys without a scope

Keys created before capabilities existed, and keys created on the organization's
account page, have no scope. They can chat and manage agents, and reach every
agent, but they **cannot** manage API keys: listing, creating or revoking keys
through the API needs a key created with `manageApiKeys`.

## Managing keys through the API

All four operations require a key with `manageApiKeys` and no agent allowlist.

| Operation                  | Behavior                                                                                                                                                                                                                         |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /v1/api-keys`         | Returns `{ "apiKeys": [...] }`. Each key has `id`, `description`, `canChat`, `canManageAgents`, `canManageApiKeys`, `allowedAgentIds`, `createdAt` and `lastUsedAt`. The secret token is never returned                          |
| `POST /v1/api-keys`        | Answers `201` with `{ "id", "token" }`. The token appears only in this response. `description` is optional, 1 to 200 characters. Omitted capabilities take the defaults above, and an omitted `allowedAgentIds` means all agents |
| `PATCH /v1/api-keys/{id}`  | Partial update: only the fields you send change. Send `description: null` to clear it. `allowedAgentIds` replaces the whole list; send `[]` to allow all agents. Editing never rotates the token, and the key id stays the same  |
| `DELETE /v1/api-keys/{id}` | Revokes the key and answers `{ "success": true, "message": "API key revoked successfully" }`                                                                                                                                     |

```bash
curl -s https://api.runbear.io/v1/api-keys \
  -H "Authorization: Bearer $RUNBEAR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Support portal",
    "canChat": true,
    "canManageAgents": false,
    "allowedAgentIds": ["<agent id>"]
  }'
```

## Revoking

Revoking a key takes effect immediately and cannot be undone. Requests using it
fail with `401` `api_key_invalid`, so switch the consumer to its replacement
first. Revoke on **Settings → API keys**, on the organization's account page, or
with `DELETE /v1/api-keys/{id}`.

## Authentication errors

A `401` carries a `code` that says why:

| `code`               | Meaning                                    | What to do                        |
| -------------------- | ------------------------------------------ | --------------------------------- |
| `credential_missing` | No `Authorization` header                  | Send the key                      |
| `api_key_invalid`    | The key is unknown or revoked              | Fix the key; retrying cannot help |
| `pass_invalid`       | A Web SDK session pass failed verification | Start a new session               |
| `pass_expired`       | A Web SDK session pass expired             | Renew it once and retry           |

Only `pass_expired` is retryable. Treat a code you don't recognize as terminal:
the list only grows.

When key validation itself is throttled, the request fails with `429` and a
`Retry-After` header rather than a `401`. The key is fine; wait and retry. For
every `403` and `429` code, see [Errors and limits](/api/errors-and-limits.md).

## Related

- [REST API overview](/api/overview.md)
- [Errors and limits](/api/errors-and-limits.md)
- [Web SDK session mode](/api/web-sdk/authentication.md) — session passes for browsers
- [MCP server](/api/mcp-server.md) — manage agents from an AI client, authenticated by OAuth rather than a key
