Scopes
A scope is a permission attached to a key. The key can reach a route only if it holds that route's scope, so the blast radius of a leaked key is exactly the scopes you gave it — no more.
Scopes read as resource:verb: chatbots:read, knowledge:write,
chat:send.
Write implies read
Granting chatbots:write also grants chatbots:read. You never need to tick
both, and ticking only the write is not a mistake.
This exists because the alternative is worse: an integration that can create a chatbot but cannot read one back is not useful, and forcing people to enumerate both pairs leads to over-granting by habit.
An analytics job that only reads conversations needs `conversations:read` and nothing else. If it is ever compromised, that is the whole exposure.
The catalogue
This table is generated from the API itself, so it cannot drift from what the server enforces.
High-risk scopes
One scope is treated as high-risk: profile:write, because it changes
account-level details rather than content.
High-risk scopes are:
- Owner-only at mint. A team member cannot create a key that holds one.
- Excluded from "select all". They have to be ticked deliberately.
- Confirmed individually. The dashboard asks about each one separately, and the server rejects a request that has not confirmed the specific scope.
- Never grantable to a Personal Access Token.
A key missing a scope gets `403 INSUFFICIENT_SCOPE`, and the error lists what was required and what was missing. A resource belonging to *another account* gets `404 NOT_FOUND` instead — the API will not confirm that someone else's id exists.
Working out which you need
Every endpoint in the reference shows its required scope. Two rules cover the rest:
- GET and HEAD need `:read`. A handful of POSTs that only compute an answer — semantic search, the removal preview, URL validation — also take `:read`, because they change nothing.
- Everything that changes state needs `:write`, or `:send` for chat.
GET /v1/me needs no scope at all, which makes it the right way to check that
a key works and to see what it actually holds:
curl https://api.agentency.com/v1/me \
-H "Authorization: Bearer <YOUR_KEY>"{
"object": "account",
"id": 1,
"name": "Acme Support",
"key": {
"object": "api_key",
"id": 1,
"mode": "test",
"scopes": ["chatbots:read", "knowledge:write", "chat:send"],
"last_used_at": "2026-01-01T00:00:00+00:00"
}
}Changing the scopes on a key
You cannot. Scopes are fixed when a key is minted, which means a compromised key cannot be quietly widened — by you or by anyone holding it.
To change them, mint a new key with the scopes you want, deploy it, then revoke the old one. Rotation gives you a 24-hour overlap so this does not need a maintenance window.
What is deliberately absent
There is no scope that lets a key mint another key. Credential management lives in the dashboard behind a human login, so a leaked key can never escalate itself into a wider one.
The same reasoning removed team administration and checkout from the API: inviting colleagues and entering card details are things a person does in a browser, not things an integration should be able to do with a bearer token.
What's next
- Authentication — how keys are sent and verified.
- Security — storage, rotation, and what to do after a leak.
- Errors — the difference between 401, 403 and 404 here.