Ask before a sensitive action
Bind a token to one action, ask AuthFI whether the agent may do it, and wait for a person to approve when a rule requires one.
Before an AI agent does something that matters, such as sending money or merging code, it asks AuthFI. The answer is allow, deny or approval_required. Use this guide to add that question to your agent, and to wait for a person when the answer is approval_required.
Before you begin
You need:
- A registered agent and its access token. See Give an AI agent an identity.
- The permission for the action it asks about, given to the agent through a role, and a capability granted for it. The console shows a capability as a permission. See Limit what an agent may do.
Bind a token to the action
Exchange the agent's access token for a transaction token. A transaction token names one action and its details, and it lasts 60 seconds.
POST
/apis/regional/v1/ai/auth/transaction-tokencurl https://acme.authfi.io/apis/regional/v1/ai/auth/transaction-token \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "transfer:accounts",
"resource": "account:4821",
"context": { "amount": 1200, "currency": "USD", "account_type": "business" }
}'$ACCESS_TOKEN is the access token the agent received when it signed in.
{
"data": {
"transaction_token": "eyJhbGciOiJFZERTQSIs…",
"txn": "0b7d6a52-…",
"token_type": "N_A",
"expires_in": 60
}
}The action, resource and context are frozen inside the token. It cannot be reused for a different amount or a different account.
Before it binds a token, AuthFI checks the details against the limits on the agent's capability for the action. Details outside a limit are refused with 403 and constraint_violated, and no token is issued. See How a limit is evaluated.
export TRANSACTION_TOKEN=<the transaction_token from the response>Ask whether the action is allowed
Send the transaction token with the same action, resource and context.
POST
/apis/regional/v1/agents/authorizecurl https://acme.authfi.io/apis/regional/v1/agents/authorize \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agt_7f3a9c21",
"transaction_token": "'"$TRANSACTION_TOKEN"'",
"action": "transfer:accounts",
"resource": "account:4821",
"context": { "amount": 1200, "currency": "USD", "account_type": "business" }
}'agt_7f3a9c21 is the agent ID. The console shows it as "Client id" on the agent's Connect tab.
With the rule from Limit what an agent may do, a transfer of 1,000 or more waits for a person:
{ "data": { "decision": "approval_required", "approval_id": "3f0c2b6e-…", "reason": "policy_step_up" } }The limits on the capability are checked here again. If a limit was lowered after the token was bound, the answer is deny. Each reason is listed in The decision and its reason.
Wait for a person
When the decision is approval_required, the agent's owner or its approval group is asked. The person answers in the console:
- Open Approvals in the sidebar.
- Find the request under "Agents waiting to do something". The card shows the agent that asked and the details of the action.
- Choose Allow to approve, or Refuse to deny.
Allow asks for confirmation: the agent is told yes and goes ahead straight away, with the arguments shown. The console then shows "Approved" or "Refused".
Meanwhile the agent polls for the result, using the approval_id from the previous step.
GET
/apis/regional/v1/agents/approvals/{approval_id}{
"data": {
"approval_id": "3f0c2b6e-…",
"status": "approved",
"requesting_action": "transfer:accounts",
"approver_user_id": "5a1e…",
"created_at": "2026-10-09T10:02:11Z",
"resolved_at": "2026-10-09T10:02:48Z",
"expires_at": "2026-10-09T10:17:11Z"
}
}Check that it works
Run the three steps with an action that one of your project rules sends to a person. That is a policy with the effect "Require step-up".
- The authorize response has
"decision": "approval_required"and anapproval_id. - Poll the approval. Its
statusispending. - In the console, open Approvals. Under "Agents waiting to do something", choose Allow on the request and confirm.
- Poll again. The
statusisapproved, andapprover_user_idandresolved_atare set.
Open an approval request directly
An agent can also open an approval request without the authorize step. Use this for an action that your own code decides is sensitive.
POST
/apis/regional/v1/agents/request-approvalA client assertion is the short statement the agent signs with its private key to prove who it is. Build one as you do in Give an AI agent an identity.
The response is 202 Accepted with the approval, in the pending status. Poll it as in Wait for a person.
How an approval is decided
- A person decides. The decision is made by a signed-in person on the Approvals page. An agent cannot approve through its own credentials.
- A policy decides when to ask. An action needs approval when a project policy with the effect "Require step-up" matches it.
- No answer is a denial. A request that nobody answers expires. An expired request can never be approved.
- Everything is recorded. The request, who decided, and when are in the audit record.
Troubleshooting
Next steps
Ask a named person to approve
Ask one person, and receive an access token that names them.
Approve a tool call
How a tool call that needs approval is retried through the MCP gateway.
Accept agents at your own API
Check a transaction token in the service that performs the action.
How agent sign-in works
The model behind access tokens, transaction tokens and approvals.