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
| Status | Meaning |
|---|
pending | Awaiting reviewer decision |
approved | Reviewer approved; execution may be in progress |
denied | Reviewer denied; deferred_action marked failed |
expired | TTL elapsed (default 24 hours) without a decision |
executed | Approved and the tool API call succeeded |
failed | Approved 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.