---
title: "Human-in-the-Loop Approvals"
description: "Pause agents and require human approval before risky actions"
---

# Human-in-the-Loop Approvals

When a policy rule triggers with action `pause`, the sandbox is frozen and an approval request is created. A human must approve or reject before the agent can continue.

## How It Works

```mermaid
sequenceDiagram
    Agent->>Policy Engine: Attempt risky action
    Policy Engine->>Approval Gate: Rule triggers "pause"
    Approval Gate->>Sandbox: Pause execution
    Approval Gate->>Human: Send notification
    Human->>Approval Gate: Approve / Reject
    alt Approved
        Approval Gate->>Sandbox: Resume
    else Rejected
        Approval Gate->>Sandbox: Keep paused
    end
```

## Notification Channels

Approval requests are delivered through multiple channels:

| Channel | Description |
|---------|-------------|
| **Dashboard** | In-app approval queue at `/dashboard/approvals` |
| **Slack** | Interactive message with Approve/Reject buttons |
| **Email** | Email with one-click approve/reject links |
| **Webhook** | Custom HTTP callback for external systems |

## Slack Integration

When configured, approval requests appear as Slack messages with interactive buttons:

- **Approve** — resumes the sandbox immediately
- **Reject** — keeps the sandbox paused
- **View Details** — opens the dashboard approval page

To set up: add your Slack webhook URL in Dashboard → Settings → Integrations.

## SLA Timers & Escalation

Every approval has an SLA deadline (default: 30 minutes). If no decision is made:

1. **Escalation rules** fire based on timeout
2. Additional channels are notified
3. Auto-decisions can be configured (auto-approve, auto-reject, or destroy sandbox)

### Escalation Rule Example

```yaml
escalation_rules:
  - name: "Auto-reject after 1h"
    timeout: 1h
    action: auto_reject
  - name: "Kill sandbox after 2h"
    timeout: 2h
    action: kill
```

## API

```bash
# List pending approvals
curl -H "Authorization: Bearer $TOKEN" https://api.caged.dev/v1/approvals/pending

# Approve a request
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -d '{"decided_by":"josh@example.com","note":"Looks safe"}' \
  https://api.caged.dev/v1/approvals/{id}/approve

# Reject a request
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -d '{"decided_by":"josh@example.com","note":"Too risky"}' \
  https://api.caged.dev/v1/approvals/{id}/reject

# Get SLA report
curl -H "Authorization: Bearer $TOKEN" \
  https://api.caged.dev/v1/approvals/sla-report?period=7d
```

## Dashboard

The approvals page at `/dashboard/approvals` shows:
- Pending requests with SLA countdown timers
- Approve/Reject buttons for each request
- Full history of past decisions
- Policy name, rule, scope, and action details

