Skip to main content
By the end of this guide your organization will enforce a policy with two rules:
  1. Block any transfer worth more than $50,000.
  2. Require one approval for any transfer worth more than $10,000.
Anything at or below $10,000 matches neither rule. You will test that case too.

Before you start

1

Pick an approver

List approver candidates returns the users and roles a require_approval rule can name.
Use a role where you can. It keeps working when people join or leave. This guide uses the admin role, which the dashboard labels Manager. Use the id, not the display name. Check member_count: a role with no members can never approve.
2

Lint the rules before you save them

Validate in-flight rule array checks a rule list without saving anything. Put the block rule first: rules run in order and the first match wins, so a transfer of $60,000 must hit the block before it hits the approval.
The keys inside action_config depend on the action type. A require_approval rule needs both approvers and required_approvals. This endpoint only checks how rules interact. The field, operator, and action_config checks happen when you save, in the next step.
Try swapping the two order values and validating again. The block rule now comes second and can never match, because every transfer over $50,000 is also over $10,000. Validation returns a warning with the code shadowed_by_different_action, and a suggested_fix telling you to move the block rule up.
3

Create the draft

Create draft policy saves the same body as a draft. It requires an Idempotency-Key, so a retry after a timeout doesn’t create a second draft.
The response is the policy, with "status": "draft" and an id. Save the id as POLICY_ID. A draft is not enforced, so nothing changes for your transactions yet.Saving checks every rule as you save it. An unknown condition field returns 400 invalid_condition_field, an unsupported operator invalid_operator, and a missing or unrecognized action_config key invalid_action_config or unknown_action_config_field. Numeric condition values come back as numbers, for example "value": 50000.
4

Dry-run three transfers

Dry-run policy evaluation runs a sample request through a policy and returns the decision. Pass policy_id to evaluate the draft. Without it, the engine uses the enforced policy. Nothing is created or logged.
A $25,000 transfer skips rule 1 and matches rule 2:
Run it again with "amount_usd": "60000" and you get "result": "rejected", from rule 0. With "amount_usd": "500" neither rule matches, so the transfer is allowed: result is approved, and every rule appears in trace with matched: false. If any result surprises you, fix the draft with the rule endpoints and dry-run again. Test rules with dry-run evaluation explains every field of the trace.
5

Validate the stored draft

Validate stored draft policy runs the same checks as step 3 against what you actually saved.
Continue only when valid is true and issue_count.error is 0. Read any warnings. They usually point at a rule order you didn’t intend.
6

Send it for activation

Activate policy stages the draft for your quorum. The comment is recorded on the approval request for your approvers and the audit log.
Your quorum approvers approve the request in the dashboard. Wait for the policy.activated event, or poll Get policy until status is enforced.
7

Confirm it is enforced

Dry-run the $25,000 case again, this time without policy_id, so the engine uses the enforced policy. You should get the same decision as in step 5. Your next real transfer over $10,000 returns 202 with "status": "pending_authorization".

What to do next