Skip to main content
When the policy engine returns require_approval, Sentrail does not forward the request. Instead it stores the entire original call — method, URL, headers, body — and returns a 202 to the agent. A reviewer decides, and Sentrail replays the stored request.

Full flow

The queue_gateway_approval_request RPC

The RPC is the atomic unit that creates both the approval record and the deferred action in a single transaction:
SELECT * FROM queue_gateway_approval_request(
  p_workspace_id   => '...',
  p_audit_log_id   => '...',
  p_correlation_id => '...',
  p_agent_id       => null,
  p_agent_name     => 'my-coding-agent',
  p_tool           => 'github',
  p_action         => 'pull_request.create',
  p_requested_by   => 'my-coding-agent',
  p_risk_level     => 'high',
  p_payload        => '{"title":"Fix bug","head":"fix/123","base":"main"}',
  p_target_url     => 'https://api.github.com/repos/owner/repo/pulls',
  p_method         => 'POST',
  p_headers        => '{}',
  p_body           => '{"title":"Fix bug","head":"fix/123","base":"main"}'
);
-- Returns: { approval_request_id: uuid }

Polling for a decision

The agent polls using the correlation ID returned in the 202:
curl https://<project-ref>.supabase.co/functions/v1/gateway-proxy/status/CORRELATION_ID \
  -H "Authorization: Bearer agk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Response while pending:
{
  "ok": true,
  "status": "pending",
  "decision": "require_approval",
  "result": null,
  "killSwitch": {
    "global": false,
    "enabledAt": null,
    "enabledBy": null,
    "toolsPaused": []
  }
}
Response after execution:
{
  "ok": true,
  "status": "executed",
  "decision": "require_approval",
  "result": {
    "id": 123,
    "html_url": "https://github.com/owner/repo/pull/123",
    "number": 123
  },
  "killSwitch": { "global": false, "toolsPaused": [] }
}

Approval request status values

StatusMeaning
pendingAwaiting reviewer decision
approvedReviewer approved; execution may be in progress
deniedReviewer denied; deferred_action marked failed
expiredTTL elapsed (default 24 hours) without a decision
executedApproved and the tool API call succeeded
failedApproved but the tool API call failed

Expiry

Approval requests expire after 24 hours by default. The expire-approvals cron job marks pending requests as expired and updates their linked deferred actions.
If the kill switch is enabled between when a request is queued and when the reviewer approves it, Sentrail will re-check the kill switch state before executing the deferred action and abort if it is active.