Policy & approvals
ZenVault runs a policy engine as the authorization boundary on every money-movement. It is evaluated before anything is signed or settled and resolves to one of:
- allow — proceed as normal.
- hold — park the transfer in state
heldfor human approval; it is not signed (and reserves no nonce) until released. - reject — block it with
403and a ZenVault-owned message.
Evaluation runs after screening, so screening signals feed the decision.
Rules
Rules are ordered (your workspace rules before ZenVault global defaults); the first match wins, and no match means allow. A rule matches on any combination of:
- kind —
external,internal,contract_call,approve,eth_sign_transaction - asset / chain / destination type — allowlisted vs one-time vs contract
- amount bounds — in asset units or USD
- risk — KYT wallet risk score ≥ N, or sanctions hit
- velocity — cumulative amount over a rolling window per asset
…and produces an action (allow / hold / reject).
Modes: shadow vs enforce
Each workspace has an enforcement mode:
shadow(default) — rules are evaluated and logged, but never block a transfer. Use it to validate rules safely against real traffic.enforce— decisions take effect: holds park transfers, rejects block.
What integrators see
Policy is managed by admins in the console (rules + mode + the approvals queue). Through the API you only need to handle two effects:
| Effect | How it appears |
|---|---|
| Held | A transfer create returns state held. It stays there until an approver releases it; watch transfer.* webhooks for the transition. |
| Rejected | The create call fails with 403 and "Transfer blocked by policy: <reason>". It is not retried automatically. |
The policy decision is also recorded on the transfer's metadata.policy
(action, rule name, reason) for auditability.
Approvals
Held transfers land in the console Approvals queue, where an approver-role user:
- Releases — the transfer is submitted for signing (a fresh nonce and current fees are applied at release), moving it into the normal lifecycle.
- Rejects — the transfer is cancelled (terminal) with a recorded reason.
Every decision is written to an audit trail.