Skip to main content

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

StatusDescription
pendingWaiting for a human reviewer
approvedReviewer approved the action
rejectedReviewer rejected the action

Reviewing approvals

Dashboard

  1. Navigate to Approvals
  2. Pending approvals show the tool call details, risk signals, and the policy that triggered it
  3. Click Approve or Reject
  4. 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}.