Skip to main content
This page answers “why did my key get a 403 — or a 401?” There are three authorization 403s — scope, binding rung, target — each with its own fix, and they are the focus of this page. But a reachable route can 403 for other reasons that are NOT about your key’s authorization — KYC_REQUIRED or PLAN_LIMIT_REACHED on create, MACHINE_ARCHIVE_DENIED on archive, ORG_CLOSED on a terminally-closed org — and those are org-state or evidence failures, not “widen the key” signals. A 401, meanwhile, usually means the route is session-only and never open to keys at all. Do not rotate or widen a key over any of these — read the specific code first.

The three 403 gates — and the 401 boundary

On a route an organization key can reach, three checks run in order, each with its own 403: The middle two are easy to confuse and need different fixes. BINDING_NOT_ALLOWED means this route is above your rung — a wider key fixes it. OUT_OF_SCOPE means you may call this route, just not on that object — a wider key or a different target fixes it. Some routes return 404 instead of OUT_OF_SCOPE, deliberately: for a resource your key cannot see, “not found” and “not yours” are the same answer, and distinguishing them would leak that it exists.
The never-machine-reachable routes below are a 401, not a fourth 403. Funding, key management, memberships, billing, org settings, and org/account deletion are session-only — they do not recognise an organization key at all, so presenting one is rejected at authentication as an invalid token (401), before any scope or binding gate runs.Crucially, that 401 is not diagnostic of your key: because these routes never run org-key verification, a valid key and a revoked or malformed one get the same 401 here. So the code proves only “this route is session-only” — it does not prove your key is good, and it does not prove it is bad. Do not conclude either from it. If you actually need to know whether a key is still valid, call a management endpoint (e.g. GET /v1/agents): a 2xx/403 there means the key authenticated; a 401 there means the key itself is bad and should be rotated.

Never machine-reachable

The following are unreachable for every organization key, regardless of scopes or binding — not a setting that can be relaxed for your integration:
  • Moving money out — withdrawals, transfers to external destinations, treasury movement.
  • Approving payments — approval is where a human decides; a bearer token cannot stand in.
  • Minting or revoking API keys — with one exception: the single bundled worker key issued inside a machine agent-create.
  • Memberships and roles — inviting, removing, or re-scoping humans.
  • Billing and plan — subscription, payment method, tier.
  • Organization settings and security.
  • The organization envelope — the org spend cap and org approval rules (/v1/org/budget, /v1/org/approval-rules). Session-only. Reading them needs an Owner or Admin session; changing them is Owner-only and step-up gated. No key reaches either.
  • Deleting an organization or account.
Two different mechanisms enforce that list, and the distinction matters if you are wondering whether a capability might appear later:
  • Most have no scope at all — there is simply nothing to grant.
  • A few scope strings exist but are not grantable. Requesting one when minting a key is rejected with 400 INVALID_SCOPE, which lists the grantable set. The notable one is transactions:approve: it is held back pending its own security review, because approving a payment is the second fence — the point where a human decides — and handing that to a bearer token is a different risk class from provisioning. Treat any non-grantable scope as unavailable rather than as coming soon; only the scopes the mint UI offers are real.
The organization envelope is the one that surprises integrators. Project and team budgets are machine-writable, so PUT /v1/org/budget looks like it should be too. It is not: the org cap is the ceiling every key operates beneath, and a key that could raise its own ceiling would make the whole model decorative. Even a human Admin cannot move it — Owner only.

The recursive fence

A binding mirrors a human role rung, and a key can never exceed the human it mirrors: Team-bound keys cannot create agents because human Team Leads cannot either. If you need a team-scoped orchestrator that spawns agents, the answer is not a wider key — it is widening the human Team Lead role first, so machine and human stay in parity. A binding also never reaches the route that edits its own container’s envelope. A project-bound key cannot set its own project’s budget; that route requires an organization binding. Same for team-bound keys and their own team budget. The rule is uniform: the envelope you operate under is always set one rung above you.

Archiving is not a normal write

agents:write lets a key create, pause, and resume freely. Archiving is different — it is terminal, so a key may archive only a zombie of its own making: an agent that key lineage created, whose bundled-key re-delivery window has closed, that has never authenticated and has no activity, holds a zero balance, and whose keys no human has ever minted or revoked (any human key management — a mint or a revoke — permanently disqualifies the machine path; the agent is a human’s to archive even if every other condition holds). Anything else returns 403 MACHINE_ARCHIVE_DENIED and a human must archive from the dashboard.
MACHINE_ARCHIVE_DENIED always means escalate to a human — including the balance case. A non-zero wallet balance produces the same code (“archiving would strand them”), and it is tempting to read that as “sweep and retry.” Your key cannot — money-out is machine-denied (above). A human sweep then normally writes an outbound-transfer event, which trips the “never used, zero activity” evidence gate — so the machine path may well stay closed afterward anyway. Hand the whole thing to a human rather than retrying autonomously, and never branch on the message text (it can change; the code cannot).
See the management band for the two recoverable 409s and their replay sequences.

Quotas

Creation is capped independently of rate limits:
  • 100 creations/day by default, shared across agents, projects, and teams.
  • Resets at 00:00 UTC — not a rolling window. 429 CREATE_QUOTA_EXHAUSTED will not clear by backing off.
  • Fail-closed: if the quota store is briefly unreachable you get 503 QUOTA_UNAVAILABLE rather than an un-counted create. Retry with the same idempotency key. (Don’t confuse this with 503 CREATE_RETRYABLE, which is agent-create saga contention — a different condition, and one that project and team creates never emit.)
  • Charged per admitted attempt, never refunded. A create that clears the quota and then fails during provisioning still consumed a unit. Retrying the same key + payload within the same UTC day is never re-charged, complete or not; only resuming an incomplete attempt after 00:00 UTC costs another unit.
  • Rotating a key does not reset the counter — the quota follows the key’s lineage.

Other terminal states

On MCP, a closed organization returns 401, not 403 ORG_CLOSED. The MCP endpoint deliberately collapses every auth failure — unknown, revoked, malformed, closed org — into one indistinguishable 401, because a distinct code at an unauthenticated front door would confirm to any caller that a presented key is otherwise valid. REST can afford the specific code because its check runs later, already authenticated.So on MCP, do not read a 401 as “rotate the key.” Confirm the organization’s status over REST (or with a human) before re-minting anything.