Skip to main content
This guide covers how to manage policies and handle approval workflows using the Dfns API and SDK.

Prerequisites

  • Service account or authenticated user with policy management permissions
  • Dfns SDK installed and configured
  • Understanding of policies

Creating a policy

Create a policy that requires approval for large transactions:
import { DfnsApiClient } from '@dfns/sdk'

const dfns = new DfnsApiClient({
  baseUrl: 'https://api.dfns.io',
  // Your signer configuration
})

const policy = await dfns.policies.createPolicy({
  body: {
    name: 'Large Transaction Approval',
    activityKind: 'Wallets:Sign',
    rule: {
      kind: 'TransactionAmountLimit',
      configuration: {
        limit: '100000',
        currency: 'USD'
      }
    },
    action: {
      kind: 'RequestApproval',
      approvalGroups: [
        {
          name: 'Treasury',
          quorum: 2,
          approvers: {
            userId: {
              in: ['us-xxx-1', 'us-xxx-2', 'us-xxx-3']
            }
          }
        }
      ],
      autoRejectTimeout: 86400 // 24 hours
    },
    status: 'Active'
  }
})

console.log('Policy ID:', policy.id)

Policy rule types

Transaction amount limit

Trigger when a single transaction exceeds a threshold:
rule: {
  kind: 'TransactionAmountLimit',
  configuration: {
    limit: '100000',
    currency: 'USD'
  }
}

Transaction amount velocity

Trigger when total transaction value exceeds a limit within a time window:
rule: {
  kind: 'TransactionAmountVelocity',
  configuration: {
    limit: '500000',
    currency: 'USD',
    timeWindow: 86400 // 24 hours in seconds
  }
}

Transaction count velocity

Trigger when transaction count exceeds a limit within a time window:
rule: {
  kind: 'TransactionCountVelocity',
  configuration: {
    limit: 100,
    timeWindow: 86400
  }
}

Recipient whitelist

Trigger when recipient is NOT in the whitelist:
rule: {
  kind: 'TransactionRecipientWhitelist',
  configuration: {
    addresses: [
      '0x...address1',
      '0x...address2'
    ]
  }
}

Always trigger

Trigger on all matching activities:
rule: {
  kind: 'AlwaysTrigger',
  configuration: {}
}

Policy actions

Request approval

Require human approval before proceeding:
action: {
  kind: 'RequestApproval',
  approvalGroups: [
    {
      name: 'Finance',
      quorum: 1,
      approvers: {
        userId: { in: ['us-xxx-1', 'us-xxx-2'] }
      }
    }
  ],
  autoRejectTimeout: 86400
}

Block

Block the activity entirely:
action: {
  kind: 'Block'
}

Policy filters

Apply policies to specific wallets using tags:
const policy = await dfns.policies.createPolicy({
  body: {
    name: 'Treasury Policy',
    activityKind: 'Wallets:Sign',
    rule: {
      kind: 'TransactionAmountLimit',
      configuration: { limit: '50000', currency: 'USD' }
    },
    action: {
      kind: 'RequestApproval',
      approvalGroups: [/* ... */]
    },
    filters: {
      walletTags: {
        hasAny: ['treasury']
      }
    },
    status: 'Active'
  }
})

Listing policies

Get all policies:
const policies = await dfns.policies.listPolicies()

for (const policy of policies.items) {
  console.log(`${policy.name}: ${policy.status}`)
}

Updating a policy

Update an existing policy:
await dfns.policies.updatePolicy({
  policyId: 'pl-xxx-xxx',
  body: {
    name: 'Updated Policy Name',
    status: 'Active'
  }
})

Deleting a policy

Delete a policy:
await dfns.policies.deletePolicy({
  policyId: 'pl-xxx-xxx'
})

Working with approvals

Listing pending approvals

Get approvals awaiting action:
const approvals = await dfns.policyApprovals.listApprovals({
  query: {
    status: 'Pending'
  }
})

for (const approval of approvals.items) {
  console.log(`Approval ${approval.id}: ${approval.activity.kind}`)
}

Getting approval details

Get details for a specific approval:
const approval = await dfns.policyApprovals.getApproval({
  approvalId: 'pa-xxx-xxx'
})

console.log('Activity:', approval.activity)
console.log('Triggered policies:', approval.triggeredPolicies)
console.log('Decisions so far:', approval.decisions)

Submitting an approval decision

Approve or reject a pending approval:
// Approve
await dfns.policyApprovals.createApprovalDecision({
  approvalId: 'pa-xxx-xxx',
  body: {
    value: 'Approved',
    reason: 'Verified transaction details with finance team'
  }
})

// Reject
await dfns.policyApprovals.createApprovalDecision({
  approvalId: 'pa-xxx-xxx',
  body: {
    value: 'Rejected',
    reason: 'Recipient address not verified'
  }
})
The user submitting the decision must be in one of the approval groups defined in the policy. The initiator cannot approve their own transactions by default.

Webhook notifications

Subscribe to policy events:
await dfns.webhooks.createWebhook({
  body: {
    url: 'https://your-app.com/webhooks/dfns',
    events: [
      'policy.approval.pending',
      'policy.approval.resolved',
      'policy.triggered'
    ],
    status: 'Enabled'
  }
})
Handle approval events:
app.post('/webhooks/dfns', async (req, res) => {
  const event = req.body

  switch (event.kind) {
    case 'policy.approval.pending':
      // Notify approvers
      await notifyApprovers(event.data)
      break
    case 'policy.approval.resolved':
      // Approval completed (approved or rejected)
      await handleApprovalResolved(event.data)
      break
  }

  res.status(200).send('OK')
})

Example: Multi-tier approval

Create a policy with multiple approval tiers:
// Tier 1: Operations approval for $10k+
await dfns.policies.createPolicy({
  body: {
    name: 'Operations Approval',
    activityKind: 'Wallets:Sign',
    rule: {
      kind: 'TransactionAmountLimit',
      configuration: { limit: '10000', currency: 'USD' }
    },
    action: {
      kind: 'RequestApproval',
      approvalGroups: [{
        name: 'Operations',
        quorum: 1,
        approvers: { userId: { in: ['ops-user-1', 'ops-user-2'] } }
      }]
    },
    status: 'Active'
  }
})

// Tier 2: Finance approval for $100k+
await dfns.policies.createPolicy({
  body: {
    name: 'Finance Approval',
    activityKind: 'Wallets:Sign',
    rule: {
      kind: 'TransactionAmountLimit',
      configuration: { limit: '100000', currency: 'USD' }
    },
    action: {
      kind: 'RequestApproval',
      approvalGroups: [{
        name: 'Finance',
        quorum: 2,
        approvers: { userId: { in: ['finance-1', 'finance-2', 'finance-3'] } }
      }]
    },
    status: 'Active'
  }
})