Skip to content

Async Approvals

Non-blocking approval mode for agentic flows and long-running AI sessions.

Availability

Async approvals are available in all editions.


Overview

By default, when a tool call requires approval, the MCP connection blocks — the agent waits until a human approves or declines. This works well for interactive sessions but has two drawbacks:

  1. Client timeouts. Most MCP clients default to 30–60 s; approval can take minutes.
  2. Blocked agents. The agent cannot do other work while waiting.

Async approval mode solves both problems. Instead of blocking, the tool call returns immediately with a pending_approval status and a request_id. The agent then polls get_approval_status(request_id) until the human decides, at which point the tool executes and the result is returned in the poll response.

Agent ──▶ call tool ──▶ Preloop returns {status: "pending_approval", request_id: "..."}
Agent ──▶ get_approval_status(request_id) ──▶ {status: "pending", remaining_seconds: 280}
Agent ──▶ get_approval_status(request_id) ──▶ {status: "approved", tool_result: {...}}

Configuration

Via Policy YAML

Enable async approval on an approval workflow:

version: "1.0"
metadata:
  name: async-deploy-review

approval_workflows:
  - name: "deploy-review"
    timeout_seconds: 600
    required_approvals: 1
    async_approval: true          # ← enables async mode

tools:
  - name: "bash"
    source: mcp
    approval_workflow: "deploy-review"
    conditions:
      - expression: "args.command.contains('deploy')"
        action: require_approval

Via Web UI

  1. Navigate to ToolsApproval Workflows
  2. Edit or create a policy
  3. Toggle Async Approval on
  4. Save

Polling Flow

1. Tool Call Returns Immediately

When async approval is enabled, the tool call does not block. The agent receives:

{
  "status": "pending_approval",
  "request_id": "ar_abc123",
  "message": "Approval required. Poll get_approval_status('ar_abc123') to check."
}

2. Agent Polls for Decision

The agent calls get_approval_status(request_id) periodically:

{
  "status": "pending",
  "remaining_seconds": 280,
  "tool_name": "bash",
  "tool_args": {"command": "deploy --production"},
  "requested_at": "2026-02-17T20:00:00Z"
}

3. Human Decides

The human approves or declines via mobile app, email, Slack, or web UI.

4. Agent Receives Result

On the next poll after approval, the response includes the tool's execution result:

{
  "status": "approved",
  "tool_result": {
    "text": "Deployment completed successfully."
  },
  "approver_comment": "Looks good, ship it.",
  "resolved_at": "2026-02-17T20:02:15Z"
}

If declined:

{
  "status": "declined",
  "approver_comment": "Not ready for production yet.",
  "resolved_at": "2026-02-17T20:01:30Z"
}

State Transitions

┌─────────┐
│ pending  │──── human approves ───▶ approved ──▶ tool executes ──▶ result cached
│         │──── human declines ───▶ declined
│         │──── timeout reached ──▶ expired
└─────────┘
State Description
pending Waiting for human decision
approved Human approved; tool result available (or executing)
declined Human declined; tool not executed
expired Timeout reached without a decision

Idempotency: Once a tool result is cached on an approved request, subsequent polls return the same cached result without re-executing the tool.


Client Configuration

Because the tool call returns immediately in async mode, no client timeout increase is needed. The agent polls at its own pace.

If you are using synchronous (blocking) approval mode instead, you may need to increase your MCP client timeout. See the timeout guidance in your MCP client reference page, such as Claude Code.


API Reference

get_approval_status (MCP tool)

Called by the agent to poll approval status.

Parameter Type Required Description
request_id string Yes The approval request ID returned by the original tool call

REST Endpoints

Endpoint Description
GET /api/v1/approval-requests/{id} Get approval request details (authenticated)
POST /api/v1/approval-requests/{id}/approve Approve a request
POST /api/v1/approval-requests/{id}/decline Decline a request
POST /api/v1/approval-requests/{id}/decide Approve or decline
GET /approval/{id}/data?token={token} Public token-based access
POST /approval/{id}/decide?token={token} Public token-based decision

Best Practices

  • Set reasonable timeouts. 10 minutes (timeout_seconds: 600) works for most workflows.
  • Use with agentic flows. Async approval is ideal for automated flow executions where the agent runs unattended.
  • Combine with justification. Require agents to explain why they need the tool — reviewers see the justification in the approval notification. See Per-Tool Justification.
  • Monitor via WebSocket. Subscribe to the approvals topic for real-time approval status updates in the UI.