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 aresource: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, sowhoami reports the expanded set.
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, plusmessages:readonly if it polls delivery events. - A broadcast send needs
messages:send; it runs the same outbound pipeline as a normal send.audiences:writecovers audience membership only. - A reputation dashboard needs
agents:read, notagents:write.
admin key.
Child keys cannot escalate
A key withkeys: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.