Handle approvals#
This page covers asking for approvals — in an agent's policy, its budget or a flow — and deciding them. The concepts (who may decide, how long things wait) are in Approvals.
Before you begin#
- To decide: the editor or admin role, and to be among the approval's approvers. Viewers and auditors see approvals.
- For the API:
ASTRA_TOKENandWSas in the REST API page. The CLI has no approval commands.
Ask for an approval#
| To hold | Write |
|---|---|
| A kind of tool call | A permit rule marked @approval (and optionally @approval_wait("1h")). The connections' Writes need approval level writes it for you. |
| A run past its own limit | When reached: Ask for approval (budget.on_exceed: approval). |
| Runs past an agent's or workspace's budget | A budget with on_exceed: approval. |
| A step of a flow | An approval step. |
@id("slack-reads")
permit (principal, action == Action::"http", resource in Server::"slack")
when { resource.path like "/conversations.*" || resource.path like "/users.*" };
@id("slack-posts")
@approval("role:admin")
@approval_wait("2h")
permit (principal, action == Action::"http", resource in Server::"slack")
when { resource.method == "POST" && resource.path == "/chat.postMessage" };
See what is waiting#
Anemoi → Approvals (its count is shown in the menu) lists what waits: when it was asked, What (the call, or the step's question), From (the agent and run, or the flow, execution and step), Policy, Who decides, and when it expires. All shows decided ones too. A run waiting is tagged waiting for approval in its agent's Runs.
Editors and admins who may decide are also told by email.
$ curl -sS "$WS/approvals?state=Pending" -H "Authorization: Bearer $ASTRA_TOKEN" \
| jq -r '.items[] | [.metadata.name, .spec.kind, .spec.target, (.spec.approvers | join(",")), .spec.expires_at] | @tsv'
approval-64bf968ac66992da flow_step Tag release v2.4.0 of acme/api? role:editor 2026-10-02T19:39:40Z
Filters: state (Pending, Approved, Denied, Expired, Used),
run, agent. Newest first.

Read what the call would do#
Open the approval. What is asked shows the call (github PUT
api.github.com/repos/acme/api/pulls/7/merge), the policy that asked,
the run, agent and version, the machine holding it and since when.
The call shows its Arguments, read from that machine now —
shortened, and values that look like keys hidden — and its
fingerprint.
$ curl -sS "$WS/approvals/approval-3f1c09a7b2e44d10" -H "Authorization: Bearer $ASTRA_TOKEN"
$ curl -sS "$WS/approvals/approval-3f1c09a7b2e44d10/details" -H "Authorization: Bearer $ASTRA_TOKEN"
details asks the machine holding the call; it is not stored. For a
budget approval, spec.amount_usd is the amount asked for.
Decide#
On the approval, under Decide, write a reason if you like (the agent is told it on a denial) and press Approve or Deny.
What happens next:
- Approved: the held call goes ahead once, and the approval becomes
Used. The same call again asks again. - Denied: the call is refused, with who denied it and why.
- If the call's wait ran out before you decided, the agent was told not
yet; the approval stays
Pendingfor 24 hours from when it was asked, and if the agent makes the same call again it goes ahead on your approval. - A flow's approval step succeeds or fails, and the flow goes on.
| Refusal | Why |
|---|---|
403 NOT_AN_APPROVER |
You are not among its approvers (the message lists them). |
409 APPROVAL_NOT_PENDING |
It was decided already, or it expired. |
400 INVALID_DECISION |
decision is not approve or deny, or the reason is too long. |
Every decision is recorded with who, when and why, appears in the run's receipt and in evidence packs.