Human-in-the-Loop (HITL)

Some intents are low risk → agent executes immediately. Some are high risk → agent must obtain fresh user approval.

Flow

  1. Agent requests high-risk intent (e.g. payments.refund) with AAP assertion.
  2. Server verifies signature + delegation, sees intent requires approval.
  3. Server returns HTTP 403 with decision: "CHALLENGE" and approvalId.
  4. User is notified and approves/denies (channel chosen by app: push, email, TOTP).
  5. User approval creates a short-lived approval token bound to the exact action.
  6. Agent retries within TTL with X-AAP-Approval header.
  7. Server verifies token and allows the action.

The approval page and channel are designed by the app, not the agent. The app owns the user's MFA/approval preference (push, email, TOTP, SMS, etc.) — similar to how 2FA methods are configured. The agent only triggers the flow; the app decides how to surface it.

CHALLENGE Response

{
  "decision": "CHALLENGE",
  "reason": "HITL_REQUIRED",
  "approvalId": "apr_92fd...",
  "expiresInSec": 600,
  "methods": ["push", "email", "totp"],
  "message": "Approve refund of $120 to Vendor X?"
}

Approval Endpoints

  • GET /aap/v1/approvals/:id — Poll status (PENDING / APPROVED / DENIED)
  • POST /aap/v1/approvals/:id/approve — User approves → returns approvalToken

Agent retries with header: X-AAP-Approval: apv1=<token>

Policy Config

{
  "intents": {
    "workorders.create": { "hitl": "never" },
    "payments.refund": { "hitl": "always", "ttlSec": 600 }
  }
}
Try HITL in Playground →

Create agent → Register → Click "Refund (HITL)" → Open Approve page → Click Approve → Retry with approval.