Skip to main content
The gateway proxy is the primary entry point for agents. It authenticates the API key, classifies the action, evaluates it against your policies, and either forwards it to the tool API, blocks it, or defers it for approval. Base URL: https://<project-ref>.supabase.co/functions/v1/gateway-proxy Required scope: gateway

URL structure

POST /gateway-proxy/{tool}/{path...}
GET  /gateway-proxy/status/{correlationId}
SegmentValues
{tool}github, linear
{path}The tool API path, e.g. /repos/owner/repo/pulls

Request headers

HeaderRequiredDescription
AuthorizationYesBearer agk_...
X-Agent-IdRecommendedAgent identifier, recorded in audit logs and approval requests
Content-TypeYes (for writes)application/json

Forward a GitHub action

curl -X POST \
  "https://<project-ref>.supabase.co/functions/v1/gateway-proxy/github/repos/owner/repo/issues" \
  -H "Authorization: Bearer agk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-Agent-Id: my-coding-agent" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Fix login bug",
    "body": "The logout button is broken on mobile.",
    "labels": ["bug"]
  }'

Success response (allow)

When the action is allowed, the response body is the tool API response directly. Sentrail adds three headers:
HTTP/1.1 201 Created
X-Sentrail-Decision: allow
X-Sentrail-AuditLogId: 7c9e6679-7425-40de-944b-e07fc1f90ae7
X-Sentrail-CorrelationId: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{
  "id": 42,
  "title": "Fix login bug",
  "html_url": "https://github.com/owner/repo/issues/42",
  ...
}

Blocked response

// HTTP 403
{
  "ok": false,
  "decision": "block",
  "reason": "Policy 'Block all writes' matched",
  "auditLogId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "correlationId": "550e8400-e29b-41d4-a716-446655440000"
}

Approval required response

// HTTP 202
{
  "ok": true,
  "decision": "require_approval",
  "reason": "Policy 'Require approval for PRs' matched",
  "approvalRequestId": "550e8400-e29b-41d4-a716-446655440000",
  "auditLogId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "pollUrl": "/functions/v1/gateway-proxy/status/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Polling status

Poll for the decision using the correlation ID:
curl "https://<project-ref>.supabase.co/functions/v1/gateway-proxy/status/CORRELATION_ID" \
  -H "Authorization: Bearer agk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// Pending
{
  "ok": true,
  "status": "pending",
  "decision": "require_approval",
  "result": null,
  "killSwitch": {
    "global": false,
    "enabledAt": null,
    "enabledBy": null,
    "toolsPaused": []
  }
}

// After execution
{
  "ok": true,
  "status": "executed",
  "decision": "require_approval",
  "result": { "id": 15, "html_url": "https://github.com/owner/repo/pull/15" },
  "killSwitch": { "global": false, "toolsPaused": [] }
}

Status codes

CodeMeaning
200Action forwarded (body is tool API response)
202Action deferred for approval
400Bad request — unsupported tool, missing path, body too large
401Invalid or expired API key, or missing gateway scope
403Action blocked by policy
405Method not allowed
500Internal error — gateway proxy failure or deferred execution failure

Rate limiting

Sentrail applies a soft rate limit of 100 requests per 60 seconds per API key prefix. Requests beyond this threshold are logged as warnings but not rejected. Hard rate limiting is handled at the Supabase edge.