Approvals
The approval system provides human oversight for sensitive operations, ensuring critical actions require explicit authorization.
Why Approvals?
Some operations are too important to be fully automated:
- High-risk actions: Deleting users, bulk operations
- Compliance requirements: Regulated data access
- Cost control: Expensive operations need sign-off
- Quality assurance: Review AI-generated content before sending
How Approvals Work
Operation Requested → Risk Assessment → Approval Queue → Review → Execute/Reject
- Agent or system attempts sensitive operation
- System evaluates risk level
- Approval request created
- Admin reviews in dashboard or API
- Approved: Operation executes
- Rejected: Operation blocked
Approval Configuration
Enable for Operations
await client.settings.update({
approvals: {
enabled: true,
// Operations that require approval
requiredFor: [
'user.delete',
'agent.delete',
'bulk_operation',
'data_export',
'integration.connect'
],
// Risk-based rules
riskRules: [
{
condition: 'tool.cost > 10',
action: 'require_approval',
riskLevel: 'medium'
},
{
condition: 'tool.name matches "admin_*"',
action: 'require_approval',
riskLevel: 'high'
}
],
// Timeout settings
defaultTimeout: 86400000, // 24 hours
autoRejectOnTimeout: true
}
});
Per-Tool Approval
Require approval for specific tools:
await client.tools.update('tool-123', {
permissions: {
requireApproval: true,
approvers: ['admin@company.com'],
riskLevel: 'high'
}
});
Managing Approvals
View Pending Approvals
const pending = await client.approvals.listPending();
for (const request of pending.data) {
console.log({
id: request.id,
operationType: request.operationType,
resourceType: request.resourceType,
resourceId: request.resourceId,
riskLevel: request.riskLevel,
riskReason: request.riskReason,
requestedBy: request.requestedBy,
requestedAt: request.requestedAt,
expiresAt: request.expiresAt
});
}
Approve Request
await client.approvals.approve('request-123', {
reason: 'Verified with user, operation is legitimate'
});
Reject Request
await client.approvals.reject('request-123', {
reason: 'Operation not authorized for this resource'
});
View History
const history = await client.approvals.listHistory({
status: 'approved', // approved, rejected, expired, executed
startDate: '2024-01-01',
limit: 100
});
Risk Levels
| Level | Description | Default Timeout |
|---|---|---|
low | Minor operations | 24 hours |
medium | Standard sensitive ops | 12 hours |
high | Critical operations | 4 hours |
critical | Emergency-level risk | 1 hour |
Custom Risk Assessment
// Agent can request approval with risk details
await client.approvals.request({
operationType: 'bulk_delete',
resourceType: 'conversations',
resourceId: 'batch-123',
riskLevel: 'high',
riskReason: 'Deleting 500 conversations containing customer data',
context: {
conversationCount: 500,
dateRange: '2024-01-01 to 2024-01-31',
requestedBy: 'cleanup-agent'
}
});
Approval Workflow States
┌──────────┐ ┌──────────┐ ┌──────────┐
│ pending │───▶│ approved │───▶│ executed │
└──────────┘ └──────────┘ └──────────┘
│ │
│ ▼
│ ┌──────────┐
│ │ failed │ (execution failed)
│ └──────────┘
│
├─────────────────────────────────────▶┌──────────┐
│ │ rejected │
│ └──────────┘
│
└─────────────────────────────────────▶┌──────────┐
(timeout) │ expired │
└──────────┘
Dashboard Integration
Approval Queue
Access pending approvals in the Dashboard:
- Go to Security → Approvals
- View pending requests with risk details
- Click to expand and see full context
- Approve or reject with optional reason
Notifications
Configure notifications for pending approvals:
await client.settings.update({
approvals: {
notifications: {
email: true,
slack: true,
inApp: true,
urgentOnly: false // Only high/critical if true
}
}
});
Trusted Patterns
Create patterns for operations that don't need approval:
// Trust certain operations from specific agents
await client.approvals.createTrustedPattern({
name: 'IT Agent - User Lookup',
description: 'IT agent reading user info is safe',
conditions: {
agentId: 'it-agent-123',
operationType: 'user.read',
resourceType: 'user'
},
enabled: true
});
// Trust operations under certain thresholds
await client.approvals.createTrustedPattern({
name: 'Small Data Export',
description: 'Exports under 100 records are auto-approved',
conditions: {
operationType: 'data_export',
contextMatch: {
'recordCount': { lt: 100 }
}
}
});
List Trusted Patterns
const patterns = await client.approvals.listTrustedPatterns();
for (const pattern of patterns.data) {
console.log({
name: pattern.name,
conditions: pattern.conditions,
enabled: pattern.enabled,
matchCount: pattern.matchCount
});
}
Approval API
Request Approval
interface ApprovalRequest {
operationType: string;
resourceType: string;
resourceId: string;
riskLevel: 'low' | 'medium' | 'high' | 'critical';
riskReason: string;
context?: Record<string, any>;
expiresIn?: number; // ms
}
const request = await client.approvals.request({
operationType: 'bulk_update',
resourceType: 'agents',
resourceId: 'batch-456',
riskLevel: 'medium',
riskReason: 'Updating configuration for 50 agents',
context: {
agentCount: 50,
changedFields: ['systemPrompt', 'model']
}
});
// Wait for approval
const status = await client.approvals.waitForDecision(request.id, {
timeout: 3600000, // 1 hour
pollInterval: 5000
});
if (status.approved) {
// Proceed with operation
} else {
// Handle rejection
}
Check Approval Status
const status = await client.approvals.get('request-123');
console.log({
status: status.status,
decidedBy: status.decisionInfo?.decidedBy,
decidedAt: status.decisionInfo?.decidedAt,
reason: status.decisionInfo?.reason
});
Webhooks
Get notified of approval events:
await client.webhooks.create({
url: 'https://your-app.com/webhooks',
events: [
'approval.requested',
'approval.approved',
'approval.rejected',
'approval.expired'
]
});
Webhook Payload
{
"event": "approval.requested",
"timestamp": "2024-01-15T10:00:00Z",
"data": {
"id": "request-123",
"operationType": "bulk_delete",
"resourceType": "conversations",
"riskLevel": "high",
"riskReason": "Deleting 500 conversations",
"requestedBy": {
"type": "agent",
"id": "agent-456",
"name": "Cleanup Agent"
},
"expiresAt": "2024-01-15T14:00:00Z"
}
}
Best Practices
1. Don't Over-Approve
Require approval only for truly sensitive operations:
// ✅ Good - specific sensitive operations
requiredFor: ['user.delete', 'data_export', 'bulk_operation']
// ❌ Bad - everything needs approval (creates fatigue)
requiredFor: ['*']
2. Set Reasonable Timeouts
// High-risk: shorter timeout forces prompt decision
{ riskLevel: 'critical', timeout: 3600000 } // 1 hour
// Low-risk: longer timeout is okay
{ riskLevel: 'low', timeout: 86400000 } // 24 hours
3. Provide Context
// ✅ Good - helpful context
await client.approvals.request({
riskReason: 'Deleting 500 conversations from Jan 2024',
context: {
conversationCount: 500,
dateRange: '2024-01-01 to 2024-01-31',
sampleIds: ['conv-1', 'conv-2', 'conv-3']
}
});
// ❌ Bad - no context
await client.approvals.request({
riskReason: 'Bulk delete'
});
4. Use Trusted Patterns for Common Operations
// Reduce approval fatigue for safe, frequent operations
await client.approvals.createTrustedPattern({
name: 'Support Agent - Read User',
conditions: {
agentId: 'support-agent',
operationType: 'user.read'
}
});
Next: Learn about Audit Logs for tracking all activity.