> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentsentinel.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Approval Workflows

> Implement human-in-the-loop approval workflows for sensitive agent actions.

## Overview

The Approval Inbox enables human-in-the-loop workflows where sensitive actions require explicit human approval before execution. This is critical for:

* **High-risk operations**: Database modifications, fund transfers, user data access
* **EU AI Act compliance**: Article 14 human oversight requirements
* **Cost control**: Expensive operations requiring manager approval
* **Safety**: Actions with potential for harm

## Quick start

### 1. Mark actions as requiring approval

```python theme={null}
from agent_sentinel import guarded_action

@guarded_action(
    name="transfer_funds",
    cost_usd=0.10,
    requires_human_approval=True,
    approval_description="Transfer funds between customer accounts",
)
def transfer_funds(from_acct: str, to_acct: str, amount: float):
    # This will block until human approves/rejects
    return transfer_service.execute(from_acct, to_acct, amount)
```

### 2. Configure approval client (platform integration)

```python theme={null}
from agent_sentinel import enable_remote_sync

enable_remote_sync(
    platform_url="https://platform.agentsentinel.dev",
    api_token="as_your_api_key_here",
    run_id="run-123",
)
```

### 3. Humans review in web console

Approvers navigate to **Approvals** page and see pending requests with:

* Action description and context
* Risk level and priority
* Estimated cost
* Input parameters
* Agent intent

They can:

* **Approve** (with optional notes)
* **Reject** (with reason)
* **Request more info** (agent provides additional context)

## Approval priorities

Control urgency of approval requests:

```python theme={null}
from agent_sentinel import ApprovalClient, ApprovalPriority

client = ApprovalClient(
    platform_url="https://platform.agentsentinel.dev",
    api_token="as_your_api_key_here",
)

# Critical priority - notify immediately
response = client.request_approval_sync(
    action_name="delete_customer_data",
    description="Delete all data for customer #12345",
    agent_id="data-agent",
    run_id="run-456",
    priority=ApprovalPriority.CRITICAL,  # CRITICAL, HIGH, MEDIUM, LOW
    estimated_cost=0.0,
    timeout_seconds=300,
    action_inputs={"customer_id": 12345},
)
```

## Risk levels

Classify actions by risk:

```python theme={null}
from agent_sentinel import ApprovalClient, RiskLevel

response = client.request_approval_sync(
    action_name="modify_pricing",
    description="Update product pricing in production",
    risk_level=RiskLevel.HIGH,  # CRITICAL, HIGH, MEDIUM, LOW, MINIMAL
    # ... other params
)
```

## Handling approval responses

```python theme={null}
from agent_sentinel import ApprovalClient, ApprovalStatus

client = ApprovalClient(
    platform_url="https://platform.agentsentinel.dev",
    api_token="as_your_api_key_here",
)

response = client.request_approval_sync(
    action_name="execute_trade",
    description="Execute trade: Buy 100 shares AAPL",
    agent_id="trading-agent",
    run_id="run-789",
    estimated_cost=15000.0,
    timeout_seconds=600,  # 10 minute timeout
    action_inputs={"symbol": "AAPL", "quantity": 100, "side": "BUY"},
)

if response.status == ApprovalStatus.APPROVED:
    print(f"Approved by: {response.decided_by_email}")
    print(f"Notes: {response.decision_notes}")
    # Execute the action
    execute_trade(...)
elif response.status == ApprovalStatus.REJECTED:
    print(f"Rejected by: {response.decided_by_email}")
    print(f"Reason: {response.decision_notes}")
    # Handle rejection
elif response.status == ApprovalStatus.EXPIRED:
    print("Approval timed out - no decision within timeout window")
    # Handle timeout
elif response.status == ApprovalStatus.INFO_REQUESTED:
    print("Approver requested additional information")
    # Respond with more context
    client.respond_to_info_request(
        approval_id=response.approval_id,
        response_text="Additional context: This trade is part of rebalancing strategy..."
    )
```

## Async approval workflow

For async agents, use async methods:

```python theme={null}
from agent_sentinel import ApprovalClient

client = ApprovalClient(
    platform_url="https://platform.agentsentinel.dev",
    api_token="as_your_api_key_here",
)

async def execute_with_approval():
    response = await client.request_approval_async(
        action_name="send_customer_email",
        description="Send promotional email to 10,000 customers",
        agent_id="email-agent",
        run_id="run-999",
        estimated_cost=50.0,
        timeout_seconds=3600,  # 1 hour
    )

    if response.status == ApprovalStatus.APPROVED:
        await send_bulk_email(...)
```

## Canceling pending approvals

If circumstances change, cancel pending requests:

```python theme={null}
client.cancel_approval(approval_id="approval-123")
```

## Policy-based approval rules

Configure which actions require approval via policies:

```python theme={null}
from agent_sentinel import PolicyConfig, PolicyEngine

PolicyEngine._config = PolicyConfig(
    require_approval=True,
    approval_actions=["delete_user", "modify_prices", "transfer_funds"],
    approval_threshold_usd=100.0,  # Auto-require approval if cost > $100
    approval_timeout_seconds=600,
)
PolicyEngine._initialized = True
```

<Note>
  `PolicyEngine.configure()` is a convenience wrapper for budget/rate-limit/evidence settings; approval kwargs (`require_approval`, `approval_actions`, `approval_threshold_usd`, `approval_timeout_seconds`, `approval_tags`, `approval_risk_levels`) live on `PolicyConfig` and are typically authored via the platform UI and synced to the SDK by [`enable_remote_sync`](/sdk/python/remote-sync). For local-only configuration, assign `PolicyEngine._config` directly as shown above.
</Note>

## Approval statistics

View approval metrics via platform:

```bash theme={null}
GET /api/v1/approvals/stats
```

Returns:

* Total pending approvals
* Average decision time
* Approval vs rejection rate
* Counts by priority/risk level

## Custom approval handlers (for custom UI)

If not using the web console, implement a custom approval handler:

```python theme={null}
from agent_sentinel import HumanApprovalHandler, ApprovalRequest, ApprovalResponse, ApprovalStatus

def my_approval_handler(request: ApprovalRequest) -> ApprovalResponse:
    # Send to Slack, custom UI, etc.
    slack_response = send_slack_approval_request(
        channel="#approvals",
        action=request.action_name,
        description=request.description,
        cost=request.estimated_cost,
    )

    # Wait for human response (blocking)
    decision = wait_for_slack_response(slack_response.ts)

    return ApprovalResponse(
        request_id=request.request_id,
        status=ApprovalStatus.APPROVED if decision.approved else ApprovalStatus.REJECTED,
        decided_by_email=decision.approver_email,
        decision_notes=decision.notes,
    )

# Register handler
HumanApprovalHandler.set_approval_handler(my_approval_handler)
```

## Best practices

<Tip>
  **Set appropriate timeouts**: Critical actions should have short timeouts (5-10 min), while less urgent actions can have longer timeouts (1-24 hours).
</Tip>

<Tip>
  **Use risk levels**: Classify actions by risk to help approvers prioritize. Critical-risk items should notify immediately.
</Tip>

<Warning>
  **Handle timeouts gracefully**: Always handle `EXPIRED` status - don't assume approvals will be granted within the timeout window.
</Warning>

<Tip>
  **Provide context**: Include detailed descriptions and input parameters so approvers can make informed decisions without needing to ask for more info.
</Tip>

## See also

* [Interventions](/sdk/python/interventions) - Track blocked and escalated actions
* [Compliance](/sdk/python/compliance) - EU AI Act Article 14 human oversight
* [Policies](/sdk/python/policies) - Configure approval rules
