Skip to main content
A require_approval rule holds a matching transaction in pending_authorization until enough approvers approve it. The transaction is persisted and its funds are locked while it waits. Once approved, it signs and broadcasts without being resubmitted. This guide builds a tiered approval policy for a treasury team:

Choose your approvers

List approver candidates returns every user and role you can name. Each entry’s id and type go into the rule’s approvers list.
  • Roles ("type": "role") cover everyone who holds the role at the time a transaction is held. member_count shows how many people that is now. Prefer roles.
  • Users ("type": "user") name one person. Use them only when a specific person must sign off, and plan for that person being away.
A rule that needs more approvals than its approvers can give holds every matching transaction until it expires. Keep required_approvals below the number of people who can approve, so one absence doesn’t stop your payouts.

Write the rules

Rules run in order and the first match wins, so order them from most to least restrictive. The sweep rule comes first so automated internal moves never wait for a person.
approvers and required_approvals are both required. Saving the draft rejects a rule without them, or with an unknown key. The values destination_type takes aren’t listed in the API reference: dry-run a real transfer between your own vaults and check the value in failed_condition.actual.
Lint the rules with Validate in-flight rule array, then save them with Create draft policy. Write and activate your first policy shows both calls.

Test each tier

Dry-run one request per row of the table, against the draft. Each should stop at the rule you expect. The fourth row is worth checking closely: the sweep rule is above the block rule, so it lets a $300,000 automated sweep through. If that isn’t what you want, add an amount_usd cap to the sweep rule. When every row matches, validate the stored draft and activate it.

What approvers see

When a transfer is held, the dry-run fields required_approvals and expiry_hours describe the approval request it opens. Approvals expire after 24 hours by default. Approvers act on the request in the Bitnob dashboard. The transaction then moves on:
  • Approved: it continues to signing and broadcast, and you receive transaction.signed and then transaction.completed as normal.
  • Rejected: its status becomes rejected, which is terminal. Nothing is signed or broadcast.
  • Expired: the request lapses without enough approvals, and the transaction does not execute.
Handle held and rejected transactions covers how to show each state to your users.