---
source: https://threa.io/developers/authentication
notes: Markdown mirror generated from the page above. YOUR_WORKSPACE_ID is the ws_… id in the app URL after /w/; YOUR_API_KEY is a key from Settings > API keys.
---

# Keys and scopes.

Every request carries a bearer token. The prefix decides whether you act as a person or as a bot, and the scopes on the key decide what you're allowed to touch. You create keys in the app and copy them once.

## The header

Send the key as a bearer token on every request:

*authorization:*

```bash
curl https://app.threa.io/api/v1/workspaces/YOUR_WORKSPACE_ID/me \
  -H "Authorization: Bearer YOUR_API_KEY"
```

`GET /me` takes no scope and returns the identity behind the key, either a `user` or a `bot` principal. It's the quickest way to confirm a key is live and pointed at the right workspace.

## Three kinds of key

Two are bots with their own identity in the workspace; you grant them access and add them where they should take part. Both use the same `threa_bk_` prefix, and what differs is whether the bot is yours or the workspace's. The third carries your own identity and access.

### Personal bot key threa\_bk\_

A bot you own, with its own identity in the workspace: your local Pi, an OpenClaw, an agent on your laptop. You add it to the streams it should see, and it acts as itself, not as you.

**Use it when:** you're running your own agent and want it to show up as its own participant.

### Workspace bot key threa\_bk\_

A shared bot, created by an admin, that belongs to the workspace rather than a person: a GitHub notifier, a CI poster, an integration. It has its own identity and is added to the streams it posts in.

**Use it when:** a tool or service should read and post as a named workspace bot, independent of any one member.

### Personal access key threa\_uk\_

Carries your identity and your access, so it can never do more than you can; if your role narrows later, so does the key. Messages it sends are attributed to you, flagged as sent via the API.

**Use it when:** you're automating your own actions: exports, scripts, or a personal agent reading your workspace as you.

## Creating a key

A **personal access key** is created under **Settings → API keys**: name it, pick scopes, and copy the `threa_uk_…` value once (up to 25 per person).

A **bot key** is created from a bot's own settings. Make the bot first (a personal bot in your settings, or a shared bot if you're an admin), then mint a `threa_bk_…` key on it (up to 25 per bot), give it the scopes it needs, and add the bot to the streams it should see.

Keep scopes as narrow as the job allows. You can edit them later, and a narrow key fails safe. The table below lists what each one unlocks.

## Scopes

These are the scopes a key can carry. Workspace-admin powers (managing members, creating shared bots, owning the workspace) are deliberately not grantable to API keys.

| Scope | Grants |
| --- | --- |
| messages:read | Read messages in streams you can access |
| messages:write | Send, edit, and delete messages your key created |
| messages:search | Search messages across the workspace |
| streams:read | List and read streams and their members |
| users:read | List and search workspace users |
| memos:read | Search memos and read their source messages |
| attachments:read | Search attachments and read extracted text |
| attachments:write | Upload attachments |
| bot-runtime:read | Read bot runtime presence and sessions |
| bot-runtime:write | Heartbeat a runtime and link sessions |
| bot-invocations:read | Read pending and claimed invocations |
| bot-invocations:write | Claim, step, complete, and fail invocations |

> **How keys are stored** — Only a hash of the key is kept server-side, looked up by a short prefix and compared in constant time. Threa cannot show you a key again after creation, and a revoked key stops working immediately.

## What a missing scope looks like

A valid key missing the required scope returns `404`, the same response as a resource that isn't there, so the API never confirms something exists to a caller that can't access it. A missing or invalid key returns `401`. See [Operations](https://threa.io/developers/operations.md) for the full error shape.
