Skip to main content
Browse the documentation

Control and safety

Approvals

How an agent stops and asks before it acts, how you answer — allow, decline with feedback, or refuse — and what happens if nobody does.

Agents in Snaga can send messages, publish, call services and change data. Some of that you want done without being asked; some of it should never happen without a person saying yes. Approvals are the line between the two: before a tool call that needs permission, the run stops and waits for you.

What decides whether an agent asks

Each agent carries its own approval policy, set on the agent:

FieldWhat it does
autonomy.levelThe default. manual asks before every tool, approve_risky asks only for risky ones, full_auto asks for none.
approval_required_toolsTool names that always need a person's approval.
auto_approve_toolsTool names the agent may call without asking.
tool_overridesPer-tool trust that overrides the default: always_allow, ask_first or never_allow.

You change them with PATCH /api/v1/agents/{agentId}. Each of these list fields is replaced when you send it, not merged: send the full list you want. To change one tool's trust without touching the rest, use PATCH /api/v1/agents/{agentId}/autonomy/tool-override with tool_name and trust_level; it answers with the agent's whole override list.

In the web app, ticking Always allow this on an approval card records the same kind of per-tool choice for that agent.

The Chief of Staff can also propose a different approval policy for an agent (set_approval_policy), but a proposal changes nothing until a person applies it.

What happens when a run needs approval

  1. The run's status becomes awaiting_approval and it stops.
  2. GET /api/v1/runs/{runId} returns pending_approvals: for each waiting tool call, its id, the tool name and its args — exactly what the agent wants to do.
  3. The item appears in the company's queue of things waiting for a person, and in the web app as a card that reads Asks your permission.
curl -s https://api.snaga.ai/api/v1/runs/<run_id> \
  -H "Authorization: Bearer $SNAGA_API_KEY"

Three ways to answer

AnswerCallWhat happens to the run
AllowPOST /api/v1/runs/{runId}/approveThe tool call goes ahead and the run continues.
Decline with feedbackPOST /api/v1/runs/{runId}/reviseThe tool is not called; the agent is told why and what to change, and the run continues.
RefusePOST /api/v1/runs/{runId}/rejectThe run ends as failed with error_code: approval_rejected.

The body of approve is optional and may carry a response for the agent. Any other field is refused — you cannot "approve with approved: false"; to say no, use revise or reject.

curl -s -X POST https://api.snaga.ai/api/v1/runs/<run_id>/approve \
  -H "Authorization: Bearer $SNAGA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"response": "Go ahead, but keep it under 200 words."}'

revise is usually the right "no": the agent reads your feedback (required) as the outcome of what it tried, and does the work again differently.

curl -s -X POST https://api.snaga.ai/api/v1/runs/<run_id>/revise \
  -H "Authorization: Bearer $SNAGA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"feedback": "Do not email the customer. Draft the reply and show it to me."}'

reject takes an optional reason, which is stored on the run and becomes its error. Use it when the whole task should stop.

All three need the runs:create scope; revise and reject also need the person behind the key to have permission to approve runs. Each answers 409 if the run is not waiting for approval any more — someone may have answered first.

In the web app the card offers Allow, Don't allow and Not now. Not now sends nothing: the request keeps waiting for you.

If nobody answers

A run does not wait forever. A run still waiting for approval about 24 hours after it started is stopped, with error_code: run_approval_expired. Start the task again if it is still needed.

The record

Every decision is kept on the run, in approvals, oldest first: the decision (approved, rejected or revised), the tools it covered, decided_at, decided_by and, for a refusal or a revision, the reason. You can always see who allowed what, and when.

Everything else that waits for a person

Approvals are one of several kinds of item that wait for you. One call lists them all:

curl -s "https://api.snaga.ai/api/v1/analytics/inbox?limit=50" \
  -H "Authorization: Bearer $SNAGA_API_KEY"

counts gives the backlog by kind (approval, input, paused, failed, and review and proposal); items lists them with a one-line summary of what is being asked. It needs analytics:read. In the web app this is Needs you.

Waiting itemHow to answer
A question (awaiting_input)POST /api/v1/runs/{runId}/respond with a response. The run resumes.
A proposed change to the companyPOST /api/v1/tenants/me/proposals/{proposalId}/apply or …/reject. Only a person can apply one; an agent's credential is refused. Unanswered proposals expire after 7 days.
A mission result held for reviewPOST /api/v1/missions/{missionId}/objectives/{objectiveId}/review with a decision of accept, revise (with feedback) or reject.