Threa Developers

    Keys and scopes.

    Every request carries a bearer token. Its prefix says whether you act as a person or a bot; its scopes say what you can touch.

    The header

    Send the key as a bearer token on every request:

    Authorization header
    curl /api/v1/workspaces//me \
      -H "Authorization: Bearer "

    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 whenyou'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 whena 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 whenyou'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 Workspace 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 under Workspace Settings → Bots (a personal bot, 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.

    For a personal bot that runs a command, skip the settings pages. npx @threahq/bot connect prints a URL and a code; approve it in a browser where you're signed in, and the bot and its key are created and written to ~/.threa/bot.json on the machine that asked. The local agent recipe walks through it.

    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.

    ScopeGrants
    messages:readRead messages in streams you can access
    messages:writeSend, edit, and delete messages your key created
    messages:searchSearch messages across the workspace
    streams:readList and read streams and their members
    users:readList and search workspace users
    memos:readSearch memos and read their source messages
    attachments:readSearch attachments and read extracted text
    attachments:writeUpload attachments
    bot-runtime:readRead bot runtime presence and sessions
    bot-runtime:writeHeartbeat a runtime and link sessions
    bot-invocations:readRead pending and claimed invocations
    bot-invocations:writeClaim, 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 for the full error shape.