Skip to main content

Tool Approval API

The Tool Approval API supports human-in-the-loop authorization for agent tool calls. When an AI agent calls a tool that requires approval, the ExtProc gateway creates a pending record. The user approves or denies the request in the consent interface.

Authentication​

EndpointAuth Method
POST /api/approvalsSubject token + client assertion (dual-auth)
GET /api/approvals (sync)Client assertion (CEL)
GET /api/approvals/permanentX-Remote-User header
GET /api/approvals/{id}X-Remote-User header
POST /api/approvals/{id}/approveX-Remote-User header
POST /api/approvals/{id}/denyX-Remote-User header
POST /api/approvals/{id}/consumeSubject token (Bearer)
POST /api/approvals/{id}/revokeX-Remote-User header

Approval Flow​

ExtProc ──POST /api/approvals──▶ Broker ──(pending)──▶ User sees in UI
│
┌───────────┴───────────┐
▼ ▼
POST .../approve POST .../deny
(once|session|permanent) (optional: permanent)
│ │
▼ ▼
ExtProc ◀──GET /api/approvals (long-poll)── Broker updates sync state
│
▼ (if once + approved)
POST .../consume

Endpoints​

Create Pending Approval​

POST /api/approvals

Creates a pending approval record. Duplicate requests for one tool call return the existing record with 200. A new record returns 201.

Rate limit: The API limits each principal and agent pair to max_requests_per_minute. It returns 429 when the limit is exceeded.

Sync Approval State (Long-Poll)​

GET /api/approvals

Returns active approvals for each principal and agent pair. The endpoint supports long-poll with these headers:

  • If-None-Match: The version ETag from the previous response.
  • X-Long-Poll-Timeout: The seconds to wait for a change. The range is 1–120. The default is 30.

The endpoint returns 304 Not Modified when no change occurs before timeout. The ETag header contains the current version.

Query Parameters:

  • principal (optional): Filter results for one principal.

ExtProc retains the highest snapshot version from global and principal-filtered reads. Older responses cannot replace decisions or refresh global cache freshness. Principal-filtered reads do not advance the global polling ETag. A global response at the retained version can update the full snapshot.

Each approval summary includes server-derived tool_pattern and params_pattern. The exact tool pattern matches only the approval's tool name. The params pattern maps constrained argument names to globs. Missing argument names are unconstrained.

Each approved summary includes approved_at as an RFC 3339 timestamp. Pending and denied summaries omit this field.

The token-exchange response can include principal and agent_id. They contain the broker-verified approval identity. ExtProc denies approval-required requests when either field is absent.

Get Approval Detail​

GET /api/approvals/{id}

Returns the full detail for one approval record. The acting principal must match the approval principal.

Approve​

POST /api/approvals/{id}/approve

Changes a pending approval to approved. The request requires a persistence field:

  • once: One use. The caller must consume the approval after tool use.
  • session: Valid for the agent session duration.
  • permanent: Persists until a user revokes it. The consent interface manages it.

The request accepts params_pattern only for session or permanent. Omit it for exact coverage. With those scopes, {} leaves all arguments unconstrained. For once, every supplied params_pattern returns 422 invalid_pattern. A supplied tool_pattern returns 400 invalid_request with tool_pattern is not allowed. Malformed or non-covering parameter patterns return 422 invalid_pattern.

Scope Preview​

POST /api/approvals/{id}/scope-preview

The request accepts only params_pattern and does not change approval state. The response includes the server-derived exact tool_pattern, resolved params_pattern, and preview. A supplied tool_pattern returns 400 invalid_request with tool_pattern is not allowed.

Deny​

POST /api/approvals/{id}/deny

Changes a pending approval to denied. The request body is optional. With persistence: "permanent", the denial blocks the exact tool for that principal and agent until revocation, regardless of arguments or session. The broker clears parameter constraints for permanent denials. ExtProc also treats existing permanent denials with parameter constraints as tool-wide blocks. A permanent denial overrides matching approvals. ExtProc returns a hard denial without creating a pending approval or an approval URL.

Consume​

POST /api/approvals/{id}/consume

Marks a once approval as consumed. A repeat consume returns 200. The API returns 422 when the approval is not once or is not approved.

List Permanent Approvals​

GET /api/approvals/permanent

Returns permanent approvals and denials for the authenticated user.

Revoke Permanent Approval​

POST /api/approvals/{id}/revoke

Revokes a permanent approval or denial and changes it to denied. The API returns 422 when the approval is not permanent.

Persistence Scopes​

ScopeBehavior
onceSingle use. Must be consumed via POST .../consume after the tool executes.
sessionValid for the agent session (scoped by agent_session_id).
permanentPersists indefinitely. Visible in the consent management UI. Revocable.

Error Codes​

All error responses use the ApprovalError schema:

{
"error": "error_code",
"message": "Human-readable description"
}
CodeHTTP StatusDescription
unauthorized401Missing or invalid authentication
bad_request400Invalid request body or parameters
invalid_request400Supplied tool_pattern or another invalid request field
forbidden403Principal does not match approval owner
not_found404Approval not found
gone410Approval has expired
rate_limit_exceeded429Rate limit exceeded
not_consumable422Approval cannot be consumed
not_revocable422Approval cannot be revoked
invalid_pattern422Pattern is malformed, does not cover the reviewed call, or is supplied with once persistence
internal_error500Unexpected server error

OpenAPI Specification​

See /api/enduser/openapi.yaml for the full OpenAPI 3.0 specification.