Approvals
When a policy has the action require_approval, the tool call is paused and an approval request is created. A human must approve or reject before the agent can proceed.
How it works
Agent calls tool → Policy matches (require_approval)
│
▼
┌─────────────────┐
│ Tool call paused │
│ Status: awaiting │
└────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────┐
│ Approval request │───────→│ Notifications │
│ created │ │ (Dashboard, │
│ │ │ Slack, Email) │
└────────┬────────┘ └──────────────┘
│
├── Reviewer clicks Approve → Agent resumes
└── Reviewer clicks Reject → Agent stops / handles rejection
Approval lifecycle
| Status | Description |
|---|---|
pending | Waiting for a human reviewer |
approved | Reviewer approved the action |
rejected | Reviewer rejected the action |
Reviewing approvals
Dashboard
- Navigate to Approvals
- Pending approvals show the tool call details, risk signals, and the policy that triggered it
- Click Approve or Reject
- Optionally provide a reason
Slack
If Slack integration is configured, approval requests are sent as interactive messages. Reviewers can approve or reject directly from Slack.
API
# Approve
curl -X POST http://localhost:3000/v1/approvals/{id}/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"resolvedBy": "reviewer@company.com", "reason": "Looks safe"}'
# Reject
curl -X POST http://localhost:3000/v1/approvals/{id}/reject \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"resolvedBy": "reviewer@company.com", "reason": "Too risky"}'
SDK
// List pending approvals
const pending = await client.getApprovals('pending');
// Approve
await client.approveRequest(approvalId, 'Reviewed and safe');
// Reject
await client.rejectRequest(approvalId, 'Too risky for production');
Handling approvals in your agent
Polling approach
const tcId = await client.trackToolCall(runId, 'deploy', { env: 'production' });
// Check the decision
const run = await client.getRun(runId);
const tc = run.toolCalls?.find((t: any) => t.toolCallId === tcId);
if (tc?.status === 'awaiting_approval') {
console.log('Waiting for human approval...');
// Poll until resolved
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 10_000));
const updated = await client.getRun(runId);
const status = updated.toolCalls?.find((t: any) => t.toolCallId === tcId)?.status;
if (status === 'completed') {
console.log('Approved! Proceeding...');
break;
}
if (status === 'blocked') {
console.log('Rejected.');
break;
}
}
}
Webhook approach
Configure a webhook to receive approval decisions in real-time:
curl -X POST http://localhost:3000/v1/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-agent.com/webhook",
"events": ["approval.approved", "approval.rejected"]
}'
Audit trail
Every approval action is recorded in the audit log:
- Who created the approval request (system, triggered by policy)
- Who resolved it (human reviewer)
- When it was resolved
- The reason provided
- The original tool call context
Access audit entries for a specific approval via GET /v1/audit?entityType=approval&entityId={id}.