Governance and approvals
Governance is not a permissions layer bolted onto the API — it lives in the domain code both lanes share, so an agent hits exactly the walls a human would. This page covers how those walls surface in responses, and the approval, decision, governance, policy, and related families that operate them.
Holds are results, not errors
When a call crosses a line a human has drawn, the API prefers to succeed and report the hold over failing. The call commits, one audit event lands on the ledger, and the result tells you the action is waiting on a human:
- A Books signature act without proof returns
status: "approval_required"with the exact approval to file — see Books. crm.proposeTermspast a playbook line returnsheld: truewith the reason and aledgerId.email.sendto a first-contact recipient returnsstatus: "approval_required"and queues nothing until released.- A refused call-moderation act returns a refusal in the result with one audited
*_refusedevent. - Directory structural verbs from an agent file a review item and say so.
Three governance outcomes do surface as errors: a missing scope (403 FORBIDDEN_SCOPE), a lost race (409 CONFLICT), and a gate that blocks the act entirely (423 GOVERNANCE_NOT_READY) — used both for the decision-rights gate below and for signature proof that failed verification.
A held result is governance working as designed. Relay it plainly, quoting the ledger reference — "held for signature — ledger #ab12cd34" — and never claim a held or refused act completed. This is the one behavioral rule every client integration must get right.
The approval loop
Approvals bind a human decision to one exact action. The requester can never be the approver — that is a database constraint, not a convention — and resolving needs the approval.decide scope, which agent keys do not hold.
- Request — approval.request
File the classified action with an
actionClass, thepayload(or a precomputedpayloadHash) that binds exactly what is being approved, and an optional human-readablesubject. When a call already returned anapproval_requiredframe, file exactly theactionClass,payloadHash, andsubjectit handed you. Optionally name a board item (itemId) to block on the outcome. - Wait — GET /approval.wait
Long-poll the outcome:
GET /approval.wait?id=appr_…&timeoutMs=55000returns as soon as the approval resolves, else with its current status at the timeout (cap 55s — loop it). - A human decides
Pending approvals surface on the workspace home ("Needs you") and the Macro Pulse. A human approves or rejects; for signature acts, approving mints the cryptographic signature token bound to that exact act.
- Retry with proof
Re-issue the original call with
approvalId(or the mintedsignatureToken) in its params and a freshx-idempotency-key. The proof is single-use and bound to the org, action class, subject row, and payload hash — approve-then-swap fails closed.

approval.get and approval.list read your own approvals back; approval.resolve is the deciding verb for principals that hold approval.decide.
The decision-rights gate
A handful of methods let agents redistribute work and adopt decisions: board.decompose, board.assign, all four handoff.* verbs, decision.adopt, and decision.supersede. These refuse with 423 GOVERNANCE_NOT_READY until a workspace admin has declared who holds which decision rights (governance.set_decision_rights) — an autonomous fleet must not self-assign work before a human has said who may decide what. Check readiness with governance.status.
Decisions, policy, and the reserved namespaces
- Decisions registry —
decision.propose,comment,sign,reverse,requestAdjustment,listComments, plus the gatedadopt/supersede; read the adopted set withGET /decision.list. Signed decisions are the workspace's durable "we chose X because Y". - Policy distribution — admins publish signed policy bundles (
policy.publish); every key can fetch the current set withGET /policy(filter with?kind=). - Credential broker — org-level third-party credentials are held once, server-side: admins
credential.put/list/revoke; agentscredential.leasea short-lived, scoped credential instead of ever holding the org key. Lease results are never cached (see Idempotency). - Kill switch —
admin.deactivate/admin.reactivatehalt an agent fleet-wide; a halted agent's presence beats return ahaltdirective. - Pairing —
pairing.request(pre-auth, org-pinned, heavily throttled) thenpairing.approve(admin) is how a new agent obtains its key.
The namespaces admin, pairing, policy, and governance are reserved: their methods always require the admin scope, regardless of registry entries — defence in depth against a descriptor typo widening access.
Audit is part of the semantics
Every governance outcome — the hold, the approval, the decision, the refusal — lands on the hash-chained ledger with the acting principal, so "who tried what, who allowed it, and when" is one verifiable history. See The event ledger.