Approve risky actions before they run BETA
Surfaces used: Approval workflow (dashboard + notification channel) Modes supported: Hosted (SaaS) Self-Managed Air-Gapped Tiers: Teams Status: BETA. Approvals are shipped and usable on every deployment, including the hosted (SaaS) plan, with control-plane hardening still in flight. They are off by default -- an administrator turns them on per scope (org, project, or API key) under Settings -> Approvals.
Approvals run on the transactional policy store and are available on hosted (SaaS), self-managed, and air-gapped Control Zero. The feature is in BETA: shipped and usable, with control-plane hardening continuing. Free and Solo tiers can read the approvals UI but cannot enable it -- the flow needs a separate approver, so it starts on the Teams tier. See Set up approvals for the end-to-end guide.
What you'll do
When an AI agent attempts an action your policy marks as approval_required (production deploy, large refund, external email send), the request pauses. An approver gets a Slack / email / SMS notification with the full context, clicks Approve or Deny, and the agent either proceeds or gets a denial with reason.
Why this is the right path for you
- If you want AI agents to handle high-stakes work but refuse to let them fire-and-forget, this is the pattern.
- If your approver pool is small and predictable, the approval flow beats per-request policy edits.
- If you want to outright deny, use an ordinary DLP rule or policy. Approvals are for "sometimes yes, sometimes no" decisions.
When NOT to use this approach
If the answer is always the same ("never allow production writes from an agent"), do not wait for an approval. Write a deny rule today.
The experience
Agent -> Control Zero: invoke tool "send_refund" args {amount: $9500, customer: ...}
Control Zero: policy match "high_value_refund" -> approval-eligible deny
SDK: client.request_approval(...) -> POST approval request to the backend
Control Zero -> Slack / email / in-app bell: "Agent 'billing-bot' wants to refund $9500 to cust_123.
[ Approve ] [ Deny ] [ Open context ]"
Approver clicks Approve once / for 24h / 7d / 30d / forever.
SDK: PendingApproval.wait() resolves -> agent proceeds with the call (allow path).
The pause-and-wait primitive ships in the SDKs today: the agent calls request_approval() on an approval-eligible deny, then blocks on PendingApproval.wait() until an approver decides. Policy actions, notification channels, and the audit trail all back this flow.
How to set it up
- Tag the rule. Mark the approval-eligible rule with
escalate_on_deny: trueso a deny becomes a request instead of a hard stop. - Turn approvals on. An admin enables approvals for the scope (org, project, or API key) under Settings -> Approvals. They are off by default.
- Wire the SDK. On an approval-eligible deny, call
request_approval()andwait()(Python) /requestApproval()andwait()(Node). See the approval callback guide. - Approve from anywhere. The approver acts from the in-app bell, an email magic-link, or a connected alert channel.
Every approval is auditable: who approved, when, why, and what grant was created. See Set up approvals for the full walkthrough and Approval workflow for the decision-kind and scope model.
Prefer an always-on deny?
If the answer is always "no", do not use approvals -- write a deny rule. If you want a lightweight notify-on-deny review loop without enabling approvals, deny with a reason and route it to a channel:
- name: high_value_refund
match:
tool: send_refund
argument_gt: { amount: 1000 }
action: deny
reason: 'Refunds over $1,000 require a human approver. Reply in #approvals to authorize.'
Pair it with alert channels so the denial reason and tool arguments land in your review channel.
Common follow-ups
- "Set up the full approval flow" -> Set up approvals
- "Wire the SDK callback" -> Approval callback
- "Write a plain deny rule instead" -> Set up DLP rules
- "See what else is on the roadmap" -> Feature availability
Reference
- Concepts: Policies, Notifications
- API: API reference