FeaturesWorkspace controls

Approval for payments, messages and contact changes

Make money movement, outbound messages and contact or identity changes wait for an admin's approval: always, after the agent has read outside content, or when a recipient or account is not one you know. No learning step needed.

Some harmful actions use only legitimate values: a duplicate payment, or a larger discount than the one the customer asked for. No check on where a value came from can tell them apart from real work. For these, you choose which actions wait for a person.

The approval policy covers three kinds of action. It needs no learned contract, so it works from the moment you turn it on. Set it in the dashboard on Protection → Enforce, under Ask me before, or with the API.

KindKey in the API
Money movementPAYMENT_OR_TRANSFER
Outbound messagesCOMMUNICATE_OUT
Contact and identity changesIDENTITY_OR_AUTH

A contact or identity change is a new email address or phone number on an account, a login factor or a credential. A steered agent can take over an account with values that look legitimate, which is why it is a kind of its own.

The four modes

Each kind has its own mode.

ModeA call of that kind waits when
offNever. The default for every kind.
after_outside_contentContent written outside your organisation, such as an inbound email, an uploaded document or a web page, was read earlier in the same session.
unanchored_destinationA recipient, address or account in the call is not found in your organisation's own data or in the user's request.
alwaysAlways. Every call of that kind waits.

Until an admin chooses a policy, nothing waits, even once the workspace blocks. Before it blocks, Sentisec meanwhile records a money movement after outside content as "would ask": a preview of the recommended setting, so you can see what it would hold. The preview stops as soon as an admin saves a policy.

Outside content is judged by who wrote a tool's results. When Sentisec cannot tell whether outside content was read, the call waits under after_outside_content. That is always the case for Claude Code and Codex in subscription mode, which never show Sentisec the tool results.

What unanchored_destination checks

This mode guards where an action goes, not what it says. Sentisec looks at each destination in the call: a recipient, an address or URL, an account. If a destination's value is not backed by your organisation's own data or by the user's request, or Sentisec has no record of where it came from, the call waits. A message to a supplier whose address is in your vendor list goes out. The same message to an address that appears only in an inbound email waits.

A call that names no destination does not wait under this mode. The usual case is a reply in an existing thread, sent by thread id: it cannot be redirected to someone else. What a message reveals is the job of Sentisec's other checks, not of this mode. If every outbound message must be seen by a person, use always.

KindRecommended modeWhy
Money movementafter_outside_contentFinance teams already approve payments, and a steered payment usually goes to an account you know, so its destination does not give it away. What does is that the agent read something an outsider wrote first.
Outbound messagesunanchored_destinationA steered message gives itself away by where it goes. Messages to people your data already knows go out without a wait, so your team approves only the unusual ones.
Contact and identity changesafter_outside_contentA takeover stores an outsider's address or number, and your own record of the account says nothing about a value that is new. What gives it away is that the agent read something an outsider wrote first.

The API returns this setting as recommended.

When a call waits

The policy holds calls only once your workspace blocks, on the scoped_enforce or enforce rung of the posture ladder. There, a matching call is withheld. Its explanation says that the call awaits approval, and it appears under Approvals. An admin opens it and chooses Approve once. When the agent tries again, the approved call is released once: on an exact retry, and on a retry of the same request that only rewords free text, such as a reason or a message body. Then the arguments the approver saw are what run. Any other change is held again. How a retry is matched, who can approve and how long an approval lasts are in approve a held call once.

Each request gets its own review. When the same call is held in two requests, for example two conversations that ask for the same refund, each opens a review linked to its own session. Approving one releases that request's retry. See one review per request.

A reworded retry has to come from the same request. Suppose your application opens a new job, event or conversation for each attempt, with new task text. That attempt is a new request: only a word-for-word retry of the approved call is released there, and a retry that rewords anything asks again. Re-send the original request instead; see when your application retries.

What your application sees while a call waits:

  • The held call is withheld and explained. Its explanation says it awaits approval, and carries an offer: the address where your application reads the decision before it re-sends. How to recognise, wait and re-send is in calls waiting for approval.
  • Calls proposed with it that change something wait with it. A reply that would confirm a refund, proposed in the same answer as the held refund, is not sent. It comes back with a short explanation that it was proposed together with a call that is waiting for approval, and no review opens for it.
  • A call proposed with it that needs approval itself gets its own review. Two refunds in one answer are held as two reviews, and an admin approves each one. The agent waits once, because both were held in the same answer.
  • Calls that only read still run.
  • After the approval, the agent's retry re-proposes the calls that were not sent, and each is judged on its own. See calls proposed together.

Other cases:

  • On shadow and observe, nothing waits and no review opens. The call has already gone through, so there is nothing to approve. It is recorded on the session as "would ask", so you can see how often a person would have been asked before you move up the ladder.
  • A refusal stays a refusal. If another check refused the call, the approval policy never releases it.
  • Claude Code in subscription mode asks in its own permission prompt, on the machine where it runs.
  • Codex in subscription mode cannot ask, and an approval cannot release a call there. A matching call stays blocked.

A held call names the approval policy as the rule it waits on. Once an approval releases the agent's retry, the session records which approval released it and, for a reworded retry, which arguments the agent had reworded.

What the approver sees

The review of a held call shows:

  • The exact call: the tool and its arguments, as the agent wrote them. A workspace on metadata-only capture keeps no arguments, so its reviews show none and cannot be approved.
  • The outside content before it: which tool returned it, and what Sentisec found in it. A source reads flagged only when a check found something in it, and names what it found. Scanned, nothing found means Sentisec read it and found nothing; not fully read means it could not read all of it. When your workspace stored that content, the review can open it in place, and each such read is recorded in the audit log. Scanned, nothing found does not mean the content is safe: these content checks only inform the review, and an instruction written in ordinary business language can pass them. See what Sentisec does not catch.
  • The calls not sent with it: each call proposed in the same answer that was not sent because of this one, with a link to its step.
  • Where each argument's value came from: the user's request, your organisation's own data, outside content, or nowhere Sentisec could find.

The evidence Sentisec keeps with the review names sources and origins, never the values. Reviews opened before this evidence was recorded carry none.

Approvals, learning and testing

  • A wait is not a refusal. A session whose only holds were approval waits still teaches the next contract proposal. A call an approver rejected keeps its session out of learning.
  • Approval load is reported beside the score. When you test a contract before activating it, the calls this policy would hold are reported next to the contract's score as approval load, as calls in waits: for example "27 legitimate calls in 19 waits". Each call is one approval a person gives; calls held in the same answer are one wait for the agent. They never count as catches or as false blocks.

Which calls are covered

A tool belongs to a kind by its class: the one an admin set in protection setup, or one Sentisec proposed. A proposed class can only add a wait. Only an admin's correction takes one away.

A tool nobody has classified yet is covered only when the call itself shows the kind: an account or amount argument for money movement, a recipient argument for outbound messages. Sentisec reads that from the argument's declared type or the shape of its value, such as an IBAN or an email address, never from its name. A payment whose call shows only a bare number and a vendor id is not matched until you classify the tool. The policy lists such tools as "not yet classified". Classify them to cover every call.

No argument shows a contact or identity change: the address such a call stores looks like a message's recipient. So that kind covers only tools whose class says so, one an admin set or one Sentisec proposed. Until a contact-change tool is classified, a call that carries an email address can still wait under the outbound messages mode, because the address reads as a recipient. A phone number does not.

The policy covers these three kinds only. A write to your own records, such as setting a ticket's priority or routing it to a team, is never held by it. What Sentisec can and cannot say about such decisions is in agents that sort outside content.

Set it with the API

GET/v1/workspaces/{workspace_id}/approval-policy
The policy, what each mode means, the recommended setting, and which tools each kind covers
PUT/v1/workspaces/{workspace_id}/approval-policy
Replace the policy — admin only

These endpoints take the session token from Sentisec sign-in, like the administration endpoints, not a workspace API key. Any member can read the policy; only a workspace admin can change it. This sets the recommended setting:

curl -X PUT https://api.sentisec.ch/v1/workspaces/$SENTISEC_WORKSPACE_ID/approval-policy \
  -H "Authorization: Bearer $SENTISEC_ADMIN_TOKEN" -H "content-type: application/json" \
  -d '{"version":1,"classes":{"PAYMENT_OR_TRANSFER":"after_outside_content","COMMUNICATE_OUT":"unanchored_destination","IDENTITY_OR_AUTH":"after_outside_content"}}'
  • A PUT replaces the whole policy. A kind you leave out is off.
  • The response, like GET, carries:
    • policy, the stored setting;
    • chosen, false while no admin has chosen a policy, and preview, the recommended money setting recorded as "would ask" meanwhile (null once a policy is chosen or the workspace blocks);
    • classes, each kind with its label;
    • modes, each mode with what it means;
    • recommended, the setting above;
    • effect: asks once the workspace blocks, would_ask on shadow and observe;
    • coverage, which lists per kind the tools covered by their class (tools_in_class) and the tools not yet classified (not_yet_classified).
  • Every change is one entry in the workspace's audit log, with the previous and the new policy. Other servers pick up a change within 30 seconds.
ResponseMeaning
403 workspace_admin_requiredOnly a workspace admin can change the policy.
422 invalid_approval_policyThe body is not valid, for example an unknown mode; detail.field names the field.
503 approval_policy_class_not_migratedThe server's database cannot store contact and identity changes yet, for example a self-managed install not yet upgraded. Nothing changed.
Protected docs