Policy Configuration
How to define ALLOW, DENY, and REVIEW behavior in the Custody Engine, and how to model policy logic clearly for operational workflows.
Policy configuration is one of the central control surfaces in Blockstream Enterprise Custody. Policies determine whether actions execute immediately, are denied, or become proposals that require review.
Why this page matters
Policies apply far beyond transaction approval. You can use them to govern:
- spend requests
- wallet operations
- user creation or modification
- role and group management
- asset-management changes
Evaluation order
Policies are evaluated in descending priority order.
- the request arrives
- the system checks the highest-priority matching policy first
- the first matching policy decides the outcome
- if nothing matches, the default behavior is applied
That makes priority design important: broad catch-all policies should usually sit below more specific ones.
The core fields
| Field | Meaning |
|---|---|
resource | Which resource path the policy applies to |
action | Which action must match, such as add, edit, or delete |
priority | Evaluation order, higher first |
expression | Condition checked against the request context |
decision_on_true | ALLOW, DENY, or REVIEW |
review_expression | Required only for REVIEW; defines the approval rule |
Basic example
import { v4 as uuidv4 } from 'uuid'
const policyResult = await broadcastRequest({
action: 'add',
resource: '/policies',
details: {
plid: uuidv4(),
name: 'require-approval-for-large-transfers',
description: 'Transfers over 10000 require manager approval',
resource: `/wallets/${walletId}/spend-requests`,
action: 'add',
priority: 100,
expression:
'request.details.tx_type == "send" && request.details.request.recipients[0].amount > 10000',
decision_on_true: 'REVIEW',
review_expression: '1 OF managers',
},
})Review expressions
Review expressions define who must approve a proposal once a policy returns REVIEW.
Examples:
1 OF managers
2 OF security_team
(1 OF security_team) AND (1 OF compliance_team)What expressions can inspect
Policy expressions evaluate against the request context. Commonly used inputs include:
requestactionresourcecaller
In practice, that means you can model rules such as:
- large transfers require human approval
- only certain caller groups may initiate issuance
- only specific recipients are allowed for some wallets
- asset-management operations require compliance review
Example: multi-tier review
const policyResult = await broadcastRequest({
action: 'add',
resource: '/policies',
details: {
plid: uuidv4(),
name: 'multi-tier-approval',
resource: `/wallets/${walletId}/spend-requests`,
action: 'add',
priority: 100,
expression: 'request.details.tx_type == "issue"',
decision_on_true: 'REVIEW',
review_expression: `(1 OF ${securityGroupId}) AND (1 OF ${complianceGroupId})`,
},
})Example: whitelist-sensitive transfer review
const restrictedTransferPolicy = await broadcastRequest({
action: 'add',
resource: '/policies',
details: {
plid: uuidv4(),
name: 'whitelist-only-transfers',
resource: '/wallets/*/spend-requests',
action: 'add',
priority: 100,
expression: `
request.details.tx_type == "send" &&
getWalletRecipientGroups(request.details.wallet_id)
.includes("${sendersGroupId}") &&
request.details.request.recipients
.map(r => r.recipient.value)
.every(val => getRecipientWhitelistsByValues([val])
.includes("${approvedRecipientsWhitelistId}"))
`,
decision_on_true: 'REVIEW',
review_expression: `1 OF ${complianceGroupId}`,
},
})Practical policy-design advice
- keep high-priority policies specific
- put broad fallback policies lower in the stack
- make review expressions readable for operations teams
- separate business-logic policies from emergency lock-down policies
Related guides
API User Onboarding Workflow
How to onboard an API user to Blockstream Enterprise Custody, capture the returned device credentials, and initialize the SDK.
Wallet Onboarding Workflow
How to create and configure wallets in Blockstream Enterprise Custody, from signer creation through address generation.