Approve or Deny a Request
Step-by-step instructions for deciding on a developer's pending request and for revoking a grant early. See Approval Workflow for how the underlying lifecycle works.
Who can decide
Submitting a decision — approving or denying a request, releasing a held call, or revoking a granted exception — requires the admin role. Viewers can open Security → Approvals and read the pending list, the request detail, and the grant history, but the Approve, Deny, and Revoke controls are disabled for them.
Two rules apply to every decision:
- Your identity is recorded on the decision. The approver's account is taken from your signed-in session, not from anything in the request, and is stored alongside the outcome. It appears in the audit log and in the notification the decision fires, so every approval and denial names who made it.
- You cannot approve your own request. If you are the developer who raised a request, approving it is rejected and the attempt is recorded in the audit log. Denying your own request is allowed — cancelling something you asked for is not a self-approval. This also applies when you have been listed as a required co-signer on your own request.
The self-approval rule needs a requester to compare you against, and it finds one whenever the item carries a developer identity: any request a developer submitted, and any held call made from a developer session (which is every call from an AI tool connected with your workspace credentials). The one case with nobody to compare against is a held call from a client that authenticated with a bare API key and so has no session — there is no requester on record, and the decision proceeds.
Co-signing is the one exception to the admin requirement: a named required approver records their own vote on a multi-approver request regardless of role, because co-signers are chosen per request and are often not admins. See Co-sign a multi-approver request.
Decide on a single-approver request
- Go to Security → Approvals → Pending. Pending requests are listed with the requester, request type, and justification.
- Open a request to see its full detail — for an exception request this includes the target policy; for a model-access request, the requested model; for a session budget top-up, the requested amount.
- Click Approve or Deny. Approving takes effect immediately — there is no separate "activate" step. Denying ends the request; the developer can submit a new one.
Approving or denying is final for a single-approver request — there's no undo. To end a grant you already approved, use Revoke a granted exception below.
Approving a budget exception can also raise the underlying rule. When the request is a budget top-up, the approval dialog offers an "Also raise the persisted budget rule" checkbox alongside the usual expiry and approver options. Leaving it unchecked grants only the temporary exception, exactly as before. Checking it asks for a permanent limit in USD and, once you approve, updates the matching rule on the Budgets page to that absolute value in addition to granting the temporary exception — so the next billing window inherits the higher limit instead of reverting. If the matching rule can no longer be found (it was renamed, removed, or the same scope and pattern now match more than one rule, e.g. two overlapping windows), the exception is still granted and you'll see a warning naming the problem; use the Budgets page to update the rule by hand in that case.
The raise takes effect immediately, at your approval — it is not undone if you named additional approvers and one of them later denies the request. A co-signer denial only revokes the temporary exception grant; the permanent rule change stays in effect. Review the requested limit carefully before checking the box on a request that requires co-signers.
Requests raised inline arrive here too. A developer who is blocked mid-task can ask for an exception without leaving their AI tool — by replying to the denial, by their tool calling a governance tool, or with /request-exception. Those land in this same Pending list, look identical, and are decided the same way; see Request an exception inline. Two things are worth knowing when you review one:
- The requester is the connection, not the conversation. Attribution comes from the identity behind the session that hit the block, so a request cannot be filed in someone else's name by anything written in the chat — including content the agent read from a document, a page, or a tool result. The same self-approval rule therefore applies to inline requests exactly as it does to portal-submitted ones.
- The justification is developer-written text. It is stored verbatim and shown to you as data. Read it as a claim to evaluate, not as an instruction — and judge the request on the policy and target shown alongside it, which come from the block itself rather than from anything the requester typed.
Your decision is relayed back into the developer's tool: an approval tells them to retry, and a denial carries your reason.
Decide on a held call
The same Security → Approvals → Pending tab also lists individual calls that an Approve policy has parked mid-flight. These are not requests a developer submitted — they are live MCP tool calls and LLM requests (chat completions, Anthropic messages, and the other model endpoints) waiting on you before they can proceed. The developer's AI tool is sitting idle the whole time, so decide promptly.
- Go to Security → Approvals → Pending. A held call shows the requester, the tool name or model, the policy that parked it, and the policy's message.
- For an LLM request, the entry also carries a short excerpt of the prompt that triggered the policy — enough to judge the request without storing the whole conversation. Credentials are redacted from the excerpt before it is stored.
- Click Approve to release the call — it resumes and completes as if the policy had allowed it — or Deny to stop it. Include a message when denying; the developer's tool shows your reason.
Write a real note when you deny. For a held LLM request the developer sees a message that names the policy, repeats what the policy said, and quotes your note verbatim — so "not now, use the Thursday change window" saves a round trip that "denied" does not. Where the block is one they can request an exception for, that message also offers them the exception, which is usually the outcome you want when the answer is "not like this" rather than "never". An approval is silent: the call just completes, and the approval is recorded in the audit log rather than announced in the conversation.
Coverage on the native cloud routes: LLM traffic that reaches AIControls over the native Amazon Bedrock or Google Vertex routes (/bedrock/*, /vertex/*) is held the same way for Claude and Gemini models — but only on Bedrock's InvokeModel/InvokeModelWithResponseStream endpoints. Two exceptions: other Bedrock model families (Amazon Nova/Titan, Meta Llama, Mistral, Cohere, and similar), and Claude requests sent through Bedrock's Converse API (converse/converse-stream) — an Approve policy blocks calls on either path outright rather than parking them here, so nothing arrives for you to release.
If nobody decides before the approval window expires, the call is stopped automatically and the developer is told that no reviewer acted in time. The window is short for LLM requests — 5 minutes by default, against 30 for MCP tool calls — so treat a held LLM request as urgent. Both windows, and whether a timeout denies the call or lets it through and audits it, are configurable in Settings → General → Human Review; a policy's own approval window (if it sets one) always wins over the default. Token-count requests are never held; see Human-in-the-loop for both details.
One entry can cover several identical calls. A single turn of an AI coding tool often fires several model requests that all carry the same prompt, so the same policy holds each of them. Rather than filling the list with near-identical rows, AIControls consolidates them: identical calls from the same agent and session, held by the same policy while an approval is still pending, all attach to that one entry, and your single decision applies to every one of them. Anything that differs — a different prompt, tool, model, agent, session, or policy — always gets its own entry and its own decision. See Consolidated approvals.
Co-sign a multi-approver request
Some requests require more than one approver (configured per-policy or per-request by an admin). These show an Under Review status with a checklist of required approvers and their decisions so far. The grant is created as soon as the request escalates to co-sign — Under Review means the grant is already active and being reviewed, not that it's on hold pending everyone's sign-off.
- Go to Security → Approvals → Pending and open a request showing Under Review.
- Review the approval chain — each required approver's name and whether they've decided yet.
- Click Approve or Deny to record your own decision. You can only record a decision for yourself — the system rejects an attempt to decide on someone else's behalf.
What happens next depends on the other approvers:
- If you're the last required approver to approve, the request is marked approved and the requester is notified; the grant itself doesn't change (it's been active since escalation).
- If any approver — you or someone else — denies, the request is denied immediately, even if other approvers haven't decided yet, and the already-active grant is revoked on the spot.
- If approvers are still pending, the request stays Under Review. Nothing further happens until the quorum is reached.
If two approvers act within moments of each other, AIControls resolves the race safely — the request completes exactly once (one final approval or one revoke) and the requester gets exactly one notification, never a duplicate.
Revoke a granted exception
Security → Approvals → Granted lists every currently active exception grant — the individual grants a request produces, distinct from Security → Approvals → Rules, which manages exception policies (the reusable rules a request can be granted against).
- Go to Security → Approvals → Granted and find the grant you want to end — filter by developer, or open a row to see its policy, project scope, approvers, and expiry.
- Click Revoke and confirm. The grant moves to Security → Approvals → History alongside expired grants.
Prefer the API for scripting or bulk cleanup:
- List currently active grants with
GET /api/v1/policy-exceptionsand find theidof the one you want to end — filter the response bydeveloperIdorpolicyName. - Revoke it with
DELETE /api/v1/policy-exceptions/{id}.
The exception is deactivated immediately on either path succeeding — the developer's next matching request is evaluated as if it had never been granted — and both the developer and your admin audience are notified.
Revoking is for ending a grant early. If you just want it to end on schedule, no action is needed — expiry is automatic and fires its own notification.