Approvals
A payment needs a human when it crosses requireApprovalAbove, exceeds a budget with onBudgetExceeded: approve, is a large first payment to a new recipient, or jumps in price.
Hold mode (default). The agent’s request stays open until someone decides or approvals.timeout passes (then it’s denied). Good for CLIs and scripts.
Retry mode (hold: false). spendctl answers 402 immediately with "error": "spendctl_approval_required" and an approval id. After approval, the agent retries with X-Spendctl-Approval: <id>. An approval pays for exactly one retry.
Ways to decide
Section titled “Ways to decide”spendctl pendingspendctl approve apr_… # or --latest / --allspendctl deny apr_… --note "use the cached result"- Dashboard:
spendctl dashboard --open. - Webhooks:
format: json | slack | discord. Payloads include the reason, the CLI command and a review link. SetsecretEnvto sign payloads (X-Spendctl-Signature: sha256=…). - Review link: HMAC-bound to the admin token. Opening it (GET) only shows the request — chat apps prefetch links — and the Approve/Deny buttons POST.
Agents cannot approve: every decision needs the admin token in .spendctl/admin.token (mode 0600).