Overview
Policies define rules that govern wallet operations. Every transaction is evaluated against all active policies before signing.
- List policiesGET/policies
- Get policyGET/policies/:id
- Policy audit logGET/policies/:id/audit
- Policy statsGET/policies/stats
- List templatesGET/policies/templates
- Create policyPOST/policies
- Duplicate policyPOST/policies/:id/duplicate
- Add rule to policyPOST/policies/:id/rules
- Apply templatePOST/policies/templates/:templateId/apply
- Update policyPUT/policies/:id
- Update rulePUT/policies/:id/rules/:ruleId
- Toggle policy statusPUT/policies/:id/status
- Delete policyDELETE/policies/:id
- Remove ruleDELETE/policies/:id/rules/:ruleId
Create Policy
Use Case
Creates a new policy and (optionally) its rules in one call.
Request Body
Display name for the policy (2-255 characters). Shown across the dashboard and audit logs, so use something operators can recognise at a glance like 'Block large withdrawals'.
Optional long-form description (max 1000 chars) explaining the intent and any operational notes. Surfaces on the policy detail view.
Policy category — one of `access`, `whitelist`, `limits`, `approvals`, `velocity`, `compliance`, or `quorum`. Drives where the policy fits in evaluation order and which dashboard widgets surface it.
Evaluation priority (0-1000, default 0). Higher values evaluate first, and the first matching rule wins — bump priority on guardrails you want enforced before softer rules like `alert`.
How the policy is targeted. `all` (default) applies org-wide; `wallets`, `users`, `vaults`, or `chains` narrow it to the IDs you pass in `scope_ids`.
Identifiers the policy applies to. Must match the `scope_type` you chose — e.g., wallet UUIDs when `scope_type = wallets`. Ignored when scope is `all`.
Inline rules to attach on creation (see Rule Object below). You can also start with an empty array and add rules later via Add Rule to Policy.
Rule Object
Display name for the rule (2-255 characters). Shows alongside the policy in dashboards and audit trails.
Optional human-readable note (max 1000 chars) explaining what the rule guards against.
What happens when the rule matches: `block` rejects the transaction, `alert` lets it through but notifies, `require_approval` parks it pending approval, `require_2fa` adds a 2FA step, and `delay` queues it for delayed execution.
List of `{ field, operator, value }` triples (minimum 1). All conditions must match for the rule to fire — combine them to build precise guardrails.
Action-specific configuration. For `require_approval` this is where you set `{ "required_approvals": 2 }`; for `delay` you might set a `seconds` field, and so on.
Evaluation order within the parent policy (0-1000). Higher values evaluate first, mirroring the policy-level priority semantics.
RuleCondition
Transaction property the condition reads — common ones include `amount`, `amount_usd`, `to_address`, `chain`, `asset_id`, `direction`, `daily_volume_usd`, and `operation` (for quorum policies).
How to compare `field` to `value`: numeric (`gt`, `lt`, `gte`, `lte`), equality (`eq`, `neq`), set membership (`in`, `not_in`), or substring (`contains`).
The comparison target. For numeric operators it's a number-as-string (e.g., `"50000"`); for `in`/`not_in` it's a comma-separated list (e.g., `"policy.*,quorum.*"`).
Create Policy Response
Unique identifier for the new policy. Use it on every follow-up endpoint (update, delete, toggle, rules, audit) and pin it to your internal records.
Display name as supplied on creation. Shown in dashboards, audit logs, and approval request context.
Long-form description echoed back from the request.
Policy category (`access`, `whitelist`, `limits`, `approvals`, `velocity`, `compliance`, `quorum`). Drives evaluation grouping and dashboard placement.
`active` (currently enforced) or `inactive` (paused). Defaults to `active` immediately after creation.
Evaluation priority (0-1000). Higher values evaluate first.
`all`, `wallets`, `users`, `vaults`, or `chains`. Together with `scope_ids` controls who the policy applies to.
Identifiers the policy is scoped to. Empty array when `scope_type = all`.
`true` if this policy is marked as a reusable template that can be applied to spin up new policies.
Identifier of the template this policy was cloned from, when applicable. Empty for hand-built policies.
Number of rules currently attached to the policy. Useful for at-a-glance complexity in lists.
User who created the policy. Pairs with `created_by_name` for human-readable audit.
Display name of the creator. Safe to drop into UI without an extra user lookup.
Inline rules attached to this policy (populated when loaded with rules). Each rule carries its own `action_type`, `conditions`, `action_config`, and `priority`.
Timestamp when the policy was created.
Timestamp of the most recent metadata or rule change.
List Policies
Use Case
Lists policies in the organization.
Query Parameters
Page size. Default 20, max 100. Use with `offset` to paginate when an org has many policies.
Number of items to skip from the start of the result set. Default 0. Pair with `limit` for cursor-style paging.
Free-text search across `name` and `description`. Case-insensitive. Helpful when the org has dozens of policies and you remember a keyword.
Filter to a single category (`access`, `whitelist`, `limits`, `approvals`, `velocity`, `compliance`, or `quorum`). Useful for category-scoped dashboards.
`active` (currently enforced) or `inactive` (paused). Drops paused policies from the result set by default; pass explicitly to surface them.
List Policies Response
Each entry in data[] uses the same PolicyResponse object as Create Policy Response. Refer there for the per-field explanations. The meta envelope below carries pagination state (total, limit, offset, has_more).
Get Policy
Use Case
Retrieves a single policy by ID, including its inline rules.
Get Policy Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations.
Update Policy
Use Case
Updates a policy's metadata (name, description, category, priority, scope). Rules are managed via the policy-rule endpoints below.
Request Body
Updated policy name (2-255 characters).
Updated description (max 1000 characters).
Policy category — one of `access`, `whitelist`, `limits`, `approvals`, `velocity`, `compliance`, or `quorum`.
Evaluation priority (0-1000). Higher values evaluate first; first match wins.
Restrict policy to `all`, `wallets`, `users`, `vaults`, or `chains`.
IDs that the policy applies to (matches the `scope_type`).
Update Policy Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations.
Delete Policy
Use Case
Permanently removes a policy and its rules. If a root quorum is active, this operation is held behind a quorum approval.
Response: 204 No Content — empty body.
Toggle Policy Status
Use Case
Activate or deactivate a policy without deleting it. Inactive policies are skipped during evaluation.
Request Body
`active` to resume enforcing the policy; `inactive` to pause it without losing the configuration.
Toggle Policy Status Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations. Only status and updated_at change between calls.
Duplicate Policy
Use Case
Creates a copy of an existing policy (including its rules) under a new identifier. Useful for branching a policy to tweak before promoting.
Duplicate Policy Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations. The duplicate has a fresh id and inherits every rule from the source policy.
Get Policy Stats
Use Case
Returns aggregate counts across all policies in the organisation — useful for dashboards.
Get Policy Stats Response
Total number of policies in the organisation (active + inactive combined). Use as the headline metric on policy dashboards.
Number of policies currently in `active` status — i.e., the ones actually being evaluated against transactions.
Count of distinct policy categories currently in use. Helpful for showing coverage breadth across `limits`, `whitelist`, `velocity`, etc.
Aggregate rule count across every policy. Pair with `total_policies` to see how complex each policy is on average.
List Templates
Use Case
Returns policies marked as templates (i.e., is_template = true). Templates are reusable blueprints you apply to new configurations.
List Templates Response
Each entry in data[] uses the same PolicyResponse object as Create Policy Response. Template entries have is_template = true. Refer there for the per-field explanations.
Apply Template
Use Case
Creates a new policy from a template. The new policy inherits the template's rules and starts in active status.
Apply Template Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations. The new policy's template_id points back to the source template.
Get Policy Audit Log
Use Case
Returns the complete audit trail for a policy — every create / update / enable / disable / rule change.
Get Policy Audit Log Response
Unique identifier for the audit entry. Pin this on your side if you need to reconcile a specific change later.
Identifier of the policy this entry belongs to. Echoed for convenience even though the endpoint is policy-scoped.
What happened in this entry: `created`, `updated`, `enabled`, `disabled`, `deleted`, `duplicated` for policy-level events; `rule_added`, `rule_updated`, `rule_removed` for rule-level events.
Identifier of the user (or service account) who performed the action. Use it to chase ownership when auditing changes.
Display name of the actor — safe to drop into dashboards and notifications without an extra user lookup.
Diff of what changed in `{ field: [old, new] }` form (e.g., `{ "priority": [200, 250] }`). Empty for events that don't carry a diff like `deleted` or `rule_removed`.
Additional context the engine attaches — for example `{ "rule_id": "rule_001" }` on rule events, or approval IDs when the change went through a quorum.
When the action took place — the canonical timestamp for the entry.
Add Rule to Policy
Use Case
Adds a new rule to an existing policy. Same shape as the inline rules[] items in Create Policy.
Request Body
Rule name (2-255 characters). Shown in dashboards and audit logs.
Optional description (max 1000 characters).
What to do when the rule matches: `block`, `alert`, `require_approval`, `require_2fa`, or `delay`.
Minimum 1 condition. Each `{ field, operator, value }` triple decides when the rule fires.
Action-specific config (e.g., `{ "required_approvals": 2 }` for `require_approval`).
Rule evaluation order within the policy (0-1000). Higher values evaluate first.
Add Rule Response
Unique identifier for the new rule. Use it on Update Rule and Remove Rule, and you'll see it referenced in the policy audit log under `metadata.rule_id`.
Identifier of the policy this rule belongs to. Lets you trace a rule back to its parent in lists.
Display name as supplied on creation. Shown in the policy detail view and in approval-request context when this rule fires.
Optional long-form description, echoed back from the request. Surfaces in dashboards as supplemental context.
What this rule does on match: `block` rejects, `alert` notifies-but-allows, `require_approval` parks pending approval, `require_2fa` enforces 2FA, `delay` queues for delayed execution.
List of `{ field, operator, value }` triples that must all match for the rule to fire. Combine them to build precise guardrails like 'outbound AND amount_usd > 50000'.
Action-specific config — e.g., `{ "required_approvals": 2 }` for `require_approval`, or `{ "seconds": 3600 }` for `delay`. Empty for actions that don't need extra config (`block`, `alert`).
Evaluation order within the parent policy (0-1000). Higher values evaluate first — the first matching rule wins, so place guardrails ahead of softer rules.
Timestamp when the rule was added to the policy.
Timestamp of the most recent rule change.
Update Rule
Use Case
Patches fields on an existing rule. Only the fields you supply are replaced — others are left untouched.
Request Body
Updated rule name (2-255 characters).
Updated description (max 1000 characters).
Change the action: `block`, `alert`, `require_approval`, `require_2fa`, or `delay`.
Replacement conditions (full array replaces the existing one).
Replacement action-specific config.
Updated evaluation order (0-1000).
Update Rule Response
data is the same RuleResponse object returned by Add Rule Response. Refer there for the per-field explanations.
Remove Rule
Use Case
Permanently removes a rule from a policy.
Response: 204 No Content — empty body.
Root Quorum
The root quorum is a special policy of category quorum that governs critical administrative operations. When a quorum is active, changes to policies themselves require multi-party approval, preventing any single administrator from unilaterally modifying security controls.
Get Quorum
Use Case
Returns the current root quorum policy, or 404 if none is configured.
Get Quorum Response
Indicates whether the API request was successful.
The root quorum policy.
Quorum policy identifier.
Always `quorum`.
`active` or `inactive`.
Approval rules attached to the quorum.
Create Quorum
Use Case
Creates the root quorum policy. Only one quorum can exist per organization. Requires admin permission.
Request Body
Display name for the quorum (max 255 chars). Shown across the dashboard and audit logs — pick something operators recognise like 'Root Quorum'.
Optional long-form description (max 1000 chars) explaining the quorum's intent — useful for documenting the approval scheme alongside the policy itself.
At least one rule that decides which operations get gated. Typically `action_type: "require_approval"` with `action_config.required_approvals` set to your m-of-n threshold; conditions usually match policy/quorum admin operations.
Create Quorum Response
data is the same PolicyResponse object returned by Create Policy Response. Refer there for the per-field explanations. For the quorum specifically, category is always quorum and status is active immediately after creation.
Update / Delete Quorum
Use Case
Updates or removes the root quorum policy. If a quorum is already active, these operations themselves require quorum approval.
Update Request Body
New display name for the quorum policy. Max 255 characters; the name appears in approval-request notifications and audit logs.
Updated internal description explaining the quorum's purpose and the operations it gates. Max 1000 characters.
Replacement rule set — sending this fully replaces the existing rules rather than merging. Each rule keeps the same `action_type: "require_approval"` + `required_approvals` shape used at creation time.
Update / Delete Quorum Response
Returns a PolicyResponse (HTTP 200) when the change applies immediately. If the change itself requires quorum approval, the response is HTTP 202 with data.approval_id (uuid) and data.status: "pending" instead, and the update is held until the threshold is met via the approvals endpoints.
Approvals
Approvals are created automatically when a policy rule with action_type: "require_approval" is triggered. They can also be created by the quorum for administrative operations.
List / Get Approvals
Use Case
Lists approval requests or fetches a single one by ID.
Query Parameters (list)
Maximum number of approval requests to return per page. Defaults to 20; use together with `offset` to walk a long backlog of pending approvals.
Number of approval requests to skip before returning results — combine with `limit` to paginate through historical approvals (defaults to 0).
Filter by approval lifecycle stage: `pending` (awaiting signers), `approved` (threshold met and operation executed), `rejected` (a signer denied), `cancelled` (initiator withdrew the request) or `expired` (TTL elapsed).
List / Get Approvals Response
Indicates whether the API request was successful.
List endpoint returns an array of `ApprovalResponse` entries; the get-by-id endpoint returns a single object instead. Each entry describes one pending or completed approval request.
Stable approval request identifier — pass this to the approve / reject / cancel endpoints to act on the request.
What kind of operation is being gated: `transaction` for outbound transfers held by a policy rule, or `operation` for admin actions (policy/quorum/wallet config changes) held by the root quorum.
Reference to the transaction this approval is gating. Populated only when `approval_type` is `transaction`; the transaction stays in `pending_approval` until this approval resolves.
Current lifecycle stage: `pending` (still collecting signatures), `approved` (threshold met — operation has been executed), `rejected` (one signer denied — operation will never execute), `cancelled` (initiator withdrew) or `expired` (TTL elapsed before threshold was met).
Number of distinct signers that must approve before the operation can proceed (the `m` in m-of-n). Set by the policy or quorum rule that created this request.
Number of valid approvals collected so far. When this reaches `required_approvals` the operation executes automatically; rejections do not increment this counter.
Pagination envelope (list endpoint only) — `total`, `limit`, `offset`, `has_more`.
Approve / Reject / Cancel Request
Use Case
Records an approval, a rejection, or cancels a pending request. When the approval threshold is met, transaction approvals are signed within the Bitnob Secure Enclave automatically; operation approvals execute the underlying admin operation. Only the original requester can cancel.
Request Body (approve / reject)
Optional free-text note (max 500 chars) explaining the decision — captured in the audit trail and surfaced in the approval's `approvals[].comment` history so other signers can see the reasoning.
Approve / Reject / Cancel Response
Indicates whether the decision was recorded against the approval request.
The approval request reflecting the new state — same shape as the get-by-id response, but with an updated `status`, `current_approvals`, and an extra entry in `approvals[]`.
Approval request identifier — unchanged from the original request.
Updated lifecycle stage: `approved` if this decision met the threshold (operation executes immediately), `rejected` if this signer denied, `cancelled` if the initiator withdrew, or still `pending` when more signatures are required.
New approval count after this decision. When it equals `required_approvals` the gated operation runs automatically.
Full history of decisions on this request, including the entry just added. Each entry records who decided, what they decided, when, and the optional `comment`.