# Authentication

> Bearer API keys, workspace and scoped keys, and which tool each endpoint needs on a scoped key.

Source: https://useprimitives.com/docs/api/authentication

Every request to the cloud API carries an API key as a Bearer token. Keys are created and scoped in the dashboard; see [Auth & scoping](/docs/mcp/auth) for how scoping works across REST and MCP.

## Bearer token

Send the key in the `Authorization` header:

```bash
curl https://api.useprimitives.com/v1/groups \
  -H "Authorization: Bearer $PRIMITIVES_API_KEY"
```

## Key types

- **Workspace API keys** (`pk_…`, cloud), scoped to every group and every tool, can call every endpoint for your account.
- **Scoped API keys** (`pk_…`, cloud), limited to one group or to some tools, can reach only their group and the primitives in it, and only through endpoints their tool allowlist covers. A primitive in another group answers `404 not_found`, so its existence isn't leaked. A key for every group but only some tools works on one group per request: `/v1/primitives/{id}` finds the group from the id, `/v1/groups/{group}` names it, and `GET` or `POST /v1/primitives` needs an `X-Primitives-Group` header, or answers `400 invalid_request`. Endpoints marked **Account.** in this reference reject them with `403 forbidden`. Create and scope keys in the dashboard; see [Auth & scoping](/docs/mcp/auth).
- **Locally**, `primitives dev` listens on `127.0.0.1` only and takes no credentials.

No endpoint returns a secret's value.

## Tool allowlists

On Starter, `primitive_snapshot` and `primitive_fork` are removed from every scoped key's allowlist, since snapshots, forks and restore need Pro, Team or Enterprise. Those calls then answer `403 tool_not_allowed`, or `403 plan_limit` when nothing usable is left in the allowlist.

For API keys limited to some tools, each endpoint needs one tool on the allowlist:

| Tool | Endpoints |
| --- | --- |
| `primitive_create` | Create a primitive in the key's group |
| `primitive_snapshot` | Create a snapshot, delete a snapshot, restore |
| `primitive_fork` | Fork a primitive, only into the key's own group |
| `db_query`, `db_exec` | `query`, `exec`, `batch`, `tables` (any db tool); writes need `db_exec`. `export` needs `db_query` |
| `db_branch` | `branches` |
| `fs_read` / `fs_write` / `fs_search` / `fs_fork` | Reading / writing, moving, deleting, mkdir / `glob`, `search` / `forks` |
| `queue_send` | Send, publish |
| `queue_receive` | Receive, list and get jobs, queue counts, subscribe, unsubscribe |
| `queue_ack` | Ack, heartbeat, requeue, purge |
| `memory_remember` / `memory_recall` / `memory_forget` | Remember / recall, list, get / forget, supersede, consolidate |
| `vault_list` / `vault_use` | List secrets and grants / `fetch` |
| `kv_get` / `kv_list` | `keys/{key}`, `mget` and `export` / `keys` |
| `kv_set` / `kv_delete` | `PUT keys/{key}`, `mset`, `incr` / `DELETE keys/{key}`, `mdelete` |
| `storage_list` / `storage_read` | `objects` / reading an object or its info, `export` |
| `storage_write` | Put, copy and delete objects |
| `storage_sign` | `presign`, `presign/revoke` |

A primitive's `stats` needs its type's read tool: `db_query`, `fs_read`, `queue_receive`, `memory_recall`, `vault_list`, `kv_get` or `storage_read`. `primitive_list` is always allowed for any key that reaches the group, whatever its allowlist. Reading the group, listing primitives (`GET /primitives`), getting one (`GET /primitives/{id}`) and listing snapshots need only a key for that group. Deleting, renaming, pausing and resuming a primitive, setting and deleting secrets, creating and revoking grants, creating, listing and deleting groups, and the audit trail are account-only. A primitive outside the key's group answers `404 not_found`.
