Skip to main content

Approval Workflow

The approval workflow enables human-in-the-loop oversight for sensitive agent actions. When the policy engine determines an action requires human approval, it creates an approval task that operators can review and act upon.

Overview

The approval flow works as follows:

When Actions Escalate

Actions are escalated to approval when:

Reason CodeDescription
requires_human_approvalAction type requires explicit approval
amount_requires_approvalAmount exceeds auto-approval threshold
budget_threshold_reachedAgent is approaching daily budget limit

Approval Task Lifecycle

  1. PENDING - Task created, awaiting operator decision
  2. APPROVED - Operator approved; override token generated
  3. DENIED - Operator denied the action
  4. EXPIRED - Task expired without decision (default: 24 hours)

Managing Approvals

Via Dashboard

Navigate to /ui/approvals to see all approval tasks. From there you can:

  1. Filter by status (pending, approved, denied, expired)
  2. View approval details
  3. Approve or deny pending requests

Via API

List Approvals

# List all approvals
curl /v1/approvals \
-H "Authorization: Bearer $TOKEN"

# Filter by status
curl "/v1/approvals?status=pending" \
-H "Authorization: Bearer $TOKEN"

# Filter by UAPK ID
curl "/v1/approvals?uapk_id=my-agent" \
-H "Authorization: Bearer $TOKEN"

Get Pending Approvals

curl /v1/approvals/pending \
-H "Authorization: Bearer $TOKEN"

Get Approval Details

curl /v1/approvals/appr-abc123 \
-H "Authorization: Bearer $TOKEN"

Response:

{
"id": "uuid",
"approval_id": "appr-abc123",
"org_id": "uuid",
"interaction_id": "int-xyz789",
"uapk_id": "my-agent",
"agent_id": "my-agent-instance",
"action": {
"type": "payment",
"tool": "stripe_transfer",
"params": {
"amount": 5000,
"currency": "USD",
"recipient": "vendor-456"
}
},
"counterparty": {
"id": "vendor-456",
"type": "merchant",
"jurisdiction": "US"
},
"reason_codes": ["amount_requires_approval"],
"status": "pending",
"created_at": "2024-12-14T10:00:00Z",
"expires_at": "2024-12-15T10:00:00Z"
}

Approve an Action

curl -X POST /v1/approvals/appr-abc123/approve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"notes": "Approved after verification",
"override_token_expires_in_seconds": 300
}'

Response:

{
"approval_id": "appr-abc123",
"status": "approved",
"decided_at": "2024-12-14T10:15:00Z",
"decided_by": "user-uuid",
"override_token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"override_token_expires_at": "2024-12-14T10:20:00Z"
}

Deny an Action

curl -X POST /v1/approvals/appr-abc123/deny \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Amount too high",
"notes": "Exceeded monthly vendor limit"
}'

Get Approval Statistics

curl /v1/approvals/stats \
-H "Authorization: Bearer $TOKEN"
{
"pending": 3,
"approved": 45,
"denied": 12,
"expired": 5,
"total": 65
}

Override Tokens

When an action is approved, the gateway generates a short-lived override token. This token:

  • Is bound to the specific action (by hash)
  • Has a configurable expiry (default: 5 minutes, max: 60 minutes)
  • Can only be used once
  • Bypasses policy checks for the approved action

Using Override Tokens

The agent retries the original request with the override token:

curl -X POST /v1/gateway/execute \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"uapk_id": "my-agent",
"agent_id": "my-agent-instance",
"capability_token": "override-token-here",
"action": {
"type": "payment",
"tool": "stripe_transfer",
"params": {
"amount": 5000,
"currency": "USD",
"recipient": "vendor-456"
}
}
}'

The action in the retry must match the original action that was approved. If the parameters differ, the override token will be rejected.

Configuration

Configure approval behavior in your environment:

# How long approval tasks remain valid (hours)
GATEWAY_APPROVAL_EXPIRY_HOURS=24

# Default override token expiry (seconds)
GATEWAY_OVERRIDE_TOKEN_EXPIRY_SECONDS=300

Per-Action Escalation Rules

Configure in your UAPK manifest or organization policies:

{
"policy": {
"amount_caps": {
"max_amount": 10000,
"escalate_above": 1000
},
"require_approval": ["high_risk_transfer"],
"auto_approve": ["read_only"]
},
"constraints": {
"max_actions_per_day": 100,
"budget_escalate_at_percent": 90
}
}

Best Practices

Response Time

  • Set appropriate expiry times for your use case
  • Implement notification systems for urgent approvals
  • Consider auto-expiry for non-critical actions

Audit Trail

All approval decisions are logged:

  • Who approved/denied
  • When the decision was made
  • Notes provided
  • Override token issued (if approved)

Security

  • Only authorized users can approve/deny actions
  • Override tokens are cryptographically bound to actions
  • Expired approvals cannot be approved
  • Already-decided approvals cannot be modified

Agent Behavior

Design agents to handle escalation gracefully:

response = gateway.execute(action)

if response["decision"] == "escalate":
approval_id = response["approval_id"]
# Notify user that approval is required
# Poll for approval or use webhooks
# Retry with override token when approved

Webhooks (Coming Soon)

Configure webhooks to be notified of approval events:

{
"webhooks": {
"approval_created": "https://your-service/approvals/new",
"approval_decided": "https://your-service/approvals/decided"
}
}

Next Steps