Log in Create workspace
Skip to content

API reference

Operator - Approvals

Review held gateway actions and record an accountable approve-or-reject decision.

Jump to 3 endpoints
On this page

Overview

Approval requests pause gateway actions that policy sends to human review. The record combines the requested action, submitted payload, policy, expiry, decision, and any queued execution outcome so a reviewer can decide with context.

Decision and execution differ
Approved means the review gate passed; execution is queued separately. Read execution.status, execution.trace_id, and execution.error to determine whether the action actually ran. A rejection never requests execution.
Reviewer roles are policy data
Owner or admin status is not an automatic override when a policy names different reviewers. The decision path checks the membership role or an enabled custom workspace role against policy.reviewer_roles.
Submitted payloads remain visible
The authorizer stores attrs.payload on the approval request and returns it to operator readers without a sanitizer in this path. Callers must remove credentials, tokens, personal data, and other secrets before requesting the action.

Before you begin

  • A signed-in browser session with a selected workspace backed by an active membership is required; an archived workspace remains readable but rejects mutations. Every /api/v1/operator endpoint rejects API credentials and bearer tokens, regardless of their scopes.
  • Any role on an active membership can read the queue. A decision also requires an operating role (owner, admin, or member) and a built-in or custom reviewer role named by that request's policy.
  • Review the connector, service agent, action, reason, payload, risk policy, trace, and expiration before deciding.

How it works

  1. Triage the queue

    List requests with filter[status]=pending, open the detail, and confirm it has not expired or already been decided. Treat payload as sensitive submitted content, and correlate trace_id with observability when context is unclear.

  2. Decide, then verify

    Approve or reject once with concise notes. After an approval, re-read the request until execution reaches a terminal state; use the returned execution trace or error for follow-up.

Examples

These examples are illustrative. Replace the sample values with your own. Keep credentials in environment variables or a secret manager, never in client-side code.

Read the pending review queue

Filtering at the server keeps completed decisions out of the first-pass review list.

javascript
const response = await fetch("/api/v1/operator/approval_requests?filter%5Bstatus%5D=pending", {
  credentials: "same-origin",
  headers: {"Accept": "application/json"}
});
const body = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${body.detail}`);
console.log(body);
What to expect

200 OK with {"approval_requests": []} when no work is waiting. Each populated row includes status, action_name, policy, connector, service_agent, and execution.

Troubleshooting

Decision returns 403
Confirm the membership is not auditor and that the policy's reviewer_roles contains the built-in membership role or one of the user's enabled custom roles.
A request cannot be decided
It may already be approved, rejected, or expired. Re-read the detail instead of retrying blindly; decisions are serialized to prevent two reviewers from racing.

Endpoint reference

Ready to integrate? Open an endpoint for its required permissions, request fields, response format, and status codes. The examples above explain the workflow; these details define each individual request.

GET
/api/v1/operator/approval_requests Web Session

List approval requests

Description

Returns one page of approval requests for the current workspace, newest first. Pass next_cursor back as cursor to read older requests; it is null on the last page.

Auth

Web Session
Parameters
Name In Type Required Description
limit query integer No Maximum approval requests to return (default 50, maximum 200)
filter[status] query string No Nested status filter
filter[connector_id] query string No Nested connector UUID filter
cursor query string No Opaque next_cursor from the previous page
Responses
200

Page of approval requests with next_cursor

Returns: ApprovalRequestList

Example
{
  "approval_requests": [
    {
      "id": "a2b3c4d5-e6f7-4890-abcd-ef1234567890",
      "inserted_at": "2026-03-25T10:00:00Z",
      "payload": {
        "action": "deploy",
        "target": "production"
      },
      "request_type": "gateway_execute",
      "service_agent_id": "f4d49601-3477-4c9d-b896-ac08a26a3147",
      "status": "pending",
      "updated_at": "2026-03-25T10:00:00Z",
      "workspace_id": "4ce4d170-e6d5-4118-8f4d-fac69dc099ea"
    }
  ],
  "next_cursor": null
}
400

Invalid filter or cursor

GET
/api/v1/operator/approval_requests/:id Web Session

Get approval request details

Description

Returns details of a specific approval request.

Auth

Web Session
Parameters
Name In Type Required Description
id path string Yes Approval request UUID
Responses
200

Approval request details

Returns: ApprovalRequest

Example
{
  "id": "a2b3c4d5-e6f7-4890-abcd-ef1234567890",
  "inserted_at": "2026-03-25T10:00:00Z",
  "payload": {
    "action": "deploy",
    "target": "production"
  },
  "request_type": "gateway_execute",
  "service_agent_id": "f4d49601-3477-4c9d-b896-ac08a26a3147",
  "status": "pending",
  "updated_at": "2026-03-25T10:00:00Z",
  "workspace_id": "4ce4d170-e6d5-4118-8f4d-fac69dc099ea"
}
404

Approval request not found

POST
/api/v1/operator/approval_requests/:id/decide Web Session

Approve or deny request

Description

Makes a decision on an approval request.

Auth

Web Session
Request Body
Field Type Required Description
notes string No Optional notes for the decision
decision string (approved, rejected) Yes Decision
Parameters
Name In Type Required Description
id path string Yes Approval request UUID
Responses
200

Decision recorded

Returns: ApprovalRequest

Example
{
  "id": "a2b3c4d5-e6f7-4890-abcd-ef1234567890",
  "inserted_at": "2026-03-25T10:00:00Z",
  "payload": {
    "action": "deploy",
    "target": "production"
  },
  "request_type": "gateway_execute",
  "service_agent_id": "f4d49601-3477-4c9d-b896-ac08a26a3147",
  "status": "approved",
  "updated_at": "2026-03-25T10:00:00Z",
  "workspace_id": "4ce4d170-e6d5-4118-8f4d-fac69dc099ea"
}
400

invalid_decision — decision must be approved or rejected; or expired — the request passed its expiry and has been marked expired

403

Caller is not a reviewer for this policy, or the workspace is archived (no decision allowed). Approval is blocked in paused workspaces, while rejection may proceed if reviewer authorization passes.

404

Approval request not found

409

Approval request has already been decided

422

Validation failed, for example notes is not a string

Where to go next

see also