Govern
Documentation

Version Latest

Approvals

The Neural Inverse Govern approvals inbox for agent actions, MCP tool calls, AI Gateway tool calls and just-in-time access, with who may decide, once and session grants, notification channels and SLAs.

When a rule says "ask a named approver", the action waits for a person in Govern. All of these requests meet in one approvals inbox, in the console service Approvals (pages Inbox, Channels, SLA and Decision history).

What lands in the inbox

SourceComes fromWho may decide
agent_policyAn agent action whose rule is ask with approval: approversA named approver (or any holder of agentpolicy:approve when none is named) who also holds approvals:approve or is in the request's approver group
mcp_callAn MCP tool call that needs approvalHolders of mcp:approve
access_activationA just-in-time activation of a binding that requires approvalHolders of iam.activations:approve where the role is granted
agent_action and other subject typesThe approval service's own requests, including AI Gateway tool calls held by tool governance (action ai_gateway.tool_call)Holders of approvals:approve, or members of the request's approver group

Rules for every source:

  • The requester can never approve their own request (403 self_approval).
  • Decisions need a reason of 1 to 1000 characters.
  • A holder of approvals:read sees every request; anyone else sees what they filed, voted on, decided or may decide.
  • Every decision, and every refused attempt to decide, is audited as approvals.inbox.decided, besides the source's own audit event.

Decide an agent action

An agent permission request shows the requester, project, engine, session, kind, the action, the rule that required approval and its approvers, and whether you may decide it.

DecisionEffect
Approve onceThe action may run once. The endpoint agent consumes the grant immediately before running it; it cannot be used twice. It expires after the organisation's approval_ttl_seconds (15 minutes by default).
Approve for the sessionThe same action in the same agent session is allowed until the grant expires (session_grant_max_seconds, 8 hours by default).
DenyThe action is refused.
curl -sS -X POST "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/agent-policy/approvals/$APPROVAL_ID/decision" \
  -H "Authorization: Bearer $APPROVER_TOKEN" -H 'Content-Type: application/json' \
  -d '{"decision": "approve", "scope": "once", "comment": "Release 4.2 tag"}'

While a request is pending, the developer's tool call is refused with a message naming it; the agent retries once the request is approved. A request nobody decides expires. Govern re-evaluates the action against the person's current policy every time it is asked, so a revocation or a changed rule takes effect before a stored request is answered.

Only the approver's own vote decides an agent request. If someone else voted on the shared request through the general approvals API first, the decision answers 409 and nothing is granted.

The inbox API

RoutePurpose
GET /api/v1/approvals/inbox?view=open (or decided) &source=&cursor=&limit=One list across every source, with SLA state and can_decide for the caller
GET /api/v1/approvals/inbox/{id}One request with its reason, parameters, votes and channel dispatches
POST /api/v1/approvals/inbox/{id}/decision{"decision": "approve" or "deny", "reason", "scope"}; scope is required for items that take one (agent permissions: once or session)
GET /api/v1/approvals/settingsThe SLA and the channels, without secrets

Refusals: 403 not_an_approver or self_approval; 409 out_of_turn, already_voted, already_decided or expired; 503 source_unavailable when a source does not answer. The routes need api:access; the source decides who may act.

Notification channels

Approval requests can be sent to webhook, email, Slack and PagerDuty channels, and approved with signed single-use links. Configuring channels (POST, DELETE /api/v1/approval-channels) needs approvals:admin; reading them and dispatching a request (POST /api/v1/approvals/{id}/dispatch) need api:access. Channel URLs and credentials are never shown back; error messages are cut to the scheme and host.

A person who may decide a request can get a single-use token for it (POST /api/v1/approvals/{id}/issue-token), which POST /api/v1/approvals/redeem accepts once.

SLA

PUT /api/v1/approvals/sla (approvals:admin) sets the account's thresholds: warn_after_mins, escalate_after_mins, auto_reject_after_mins and escalation_target_group, each 1 to 43200 minutes, in that order. The inbox shows each item's SLA state (on_track, warning, escalation_due, escalated, overdue, and once decided met, late, auto_rejected or expired).

SLA processing and recurring approvals are recorded as partial in the source. Do not rely on automatic escalation or auto-rejection without testing it in your deployment.

Last reviewed 17 October 2026View as Markdown

Approvals · Docs · Neural Inverse