Skip to main content
Dry-run policy evaluation answers one question: what would the policy do with this request? It has no side effects. No transaction is created, no approval request is opened, and nothing is written to the audit log. You can call it as often as you like, against any policy, in any status.

Which policy is evaluated

  • With policy_id: that policy, whatever its status. Use this to test a draft before activation.
  • Without policy_id: the policy your organization currently enforces. Use this to check live behavior.
If you leave out policy_id and your organization has no enforced policy and no quorum, the result is "approved" with allowed: true and the reason “No active policy and no quorum”. That tells you nothing about your rules, so always pass policy_id when testing a draft.

Build the request

Every field in the request is optional. A field you leave out counts as not applicable, so a condition on that field won’t match. Send the fields your rules depend on, with the values a real transfer would carry.
A rule on actor_type never matches when you leave actor_type out. If your rules treat API keys and dashboard users differently, send apikey or session in every test.

Read the response

The top-level fields are the decision: trace shows the path. There is one entry per rule the engine reached, in order:
  • matched: false with reason and failed_condition tells you the first condition that stopped the rule, with the expected value and the actual value from your request. Later conditions in that rule were not checked.
  • terminal: true marks the rule that ended evaluation. Rules after it don’t appear.
When no rule matches, trace lists every rule with matched: false, and result is approved. trace is left out when your organization has nothing enforced and you don’t pass policy_id.

Debug a surprising result

Keep a regression suite

Policies change, and a rule order that was right last month can shadow a new rule. Keep a list of test cases next to your policy definition, and run all of them against every new draft before you activate it.
Run each case with the draft’s policy_id, and fail the check if any field in expect differs. Run it in CI when the policy definition lives in your repository, or by hand before you send a draft to quorum. Always include the boundary values of every threshold.