Skip to main content
Every API key carries a set of scopes that decide what it can do. Give each key the narrowest set its job needs: a sender that can only send, a webhook worker that can only read, an admin key that can do everything. Scopes follow one pattern. Every resource has its own read and write pair, a read is never gated behind a write, and no scope is borrowed across resources: listing inboxes needs inboxes:read, creating one needs inboxes:write. Check what any key can do with whoami:

The scope matrix

Scopes use a resource:action grammar: a read/write pair for each resource you can change, plus a read-only scope for account data. messages:read covers the mailbox only (messages, threads, attachments) and messages:send sends messages only; everything else uses its own resource scope. Dairo Phone adds a third action scope on top of its read/write pair: phone:call places and ends live calls, separate from phone:read (list and inspect) and phone:write (buy, bind, and release numbers).

What each scope unlocks

GET /v1/whoami and GET /v1/telegram/voices need no specific scope: any valid key works. Agent verification and JWKS (GET /v1/agents/verify, GET /v1/agents/jwks, and the /.well-known/dairo-jwks.json alias) are public and need no key at all.
Scopes gate the MCP server and CLI too. The MCP server authenticates with the same key, so a tool call needs the same scope as the REST endpoint behind it: send_message needs messages:send, list_contacts and manage_contacts need contacts:read and contacts:write, and so on. A missing scope comes back as scope_missing with the exact scope named, so an agent can tell whether it needs a broader key.

Bundles for a quick start

If you would rather not enumerate fine-grained scopes, request a bundle. A bundle expands to its member scopes when the key is created, so whoami reports the expanded set.
admin grants everything, including keys:write (minting and revoking other keys) and compliance:write (data erasure). Reserve it for trusted automation; use a narrow scope list everywhere else.

Least privilege in practice

Give a key the narrowest set it actually needs:
  • A webhook receiver that only reads inbound messages needs messages:read.
  • A transactional sender needs messages:send, plus messages:read only if it polls delivery events.
  • A broadcast send needs messages:send; it runs the same outbound pipeline as a normal send. audiences:write covers audience membership only.
  • A reputation dashboard needs agents:read, not agents:write.
Narrow keys make revocation surgical and usage simple to attribute. Prefer one key per workload over a single shared admin key.

Child keys cannot escalate

A key with keys:write can mint child keys, but a child’s scopes must be a subset of the key that creates it. A messages:send-only key cannot create a key with domains:write; an admin key can create anything. A key can never grant more than it holds.
See API keys and authentication for creating, restricting, and storing keys.