Workflows

Run financial operations without manual drag

Turn recurring treasury, payment, and admin workflows into governed processes. Automate what is safe. Escalate what needs review.

Workflows dashboard
Maker, checker, watcher

Service accounts handle the routine. Humans handle the exceptions. DFNS tracks everything that happens in-between.

Events to actions

Every onchain or platform state change fires a signed webhook. Every webhook drives a workflow. No polling, no miss.

Programmable in TypeScript

No DSL to learn. Decode any ABI, call any HTTP API, query any database, post any decision. The runtime is your stack.

Audited end to end

Every action, every approval, every API call, cryptographically signed and logged. Non-repudiation without paperwork.


Workflows for new and existing systems

Compose service accounts, policies, webhooks, and actions into the automated processes that run your back office.

Compose

Build workflows
from real primitives

Service accounts, webhooks, policies, every primitive is composable. Wire them together to model anything you do today.

Service accounts

Machine identities with scoped permissions. One per workflow, one per environment. Audited like any user.

Webhooks on every event

Every state change emits a signed, idempotent event. Subscribe once, react forever. No polling, no drift.

Idempotent APIs

All endpoints accept external IDs. Retries are safe. Crashes recoverable. Duplicate requests return the initial response.

Wallets dashboard
Trigger

Events fire,
workflows run.

Inbound deposits. Pending approvals. Confirmed transactions. Policy violations. Wallet creations. Credential rotations. Every onchain or platform event can drive a workflow. The runtime is yours — DFNS delivers the signal.

Onchain events

Deposit detected, transaction confirmed, contract function called, balance crossed a threshold. Real-time across 100+ chains.

Platform events

Approval requested, wallet created, policy modified, credential rotated. Operational events, not just transactional ones.

Scheduled runs

Cron the routine. Sweep balances nightly. Rebalance yields monthly. Close books quarterly. Service accounts execute under policy on the schedule you set.

Wallets dashboard
Decide

Programmable approvals,
in TypeScript

Service accounts read pending requests, decode the ABI-encoded call data, call any HTTP API or database, and post Approve / Reject / Abstain decisions. Plain TypeScript. No DSL. Your business rules, your code.

Maker / Checker pattern

Initiators and approvers are distinct identities. The platform enforces separation of duties cryptographically — no self-approval, no shortcuts. The four-eyes principle, encoded.

ABI-aware logic

Decode any smart contract call. Apply per-function rules. Allow mint to whitelisted recipients only. Cap transfer per call. Reject unknown selectors. Sanctions-screen any address.

Escalation paths

Service accounts handle the 95% routine. Humans handle the 5% exceptions. Abstain when uncertain — humans in the same approval group take it from there. Auto-escalation, not auto-rejection.

Wallets dashboard
Audit

Every step,
signed and logged

Every action — initiated, approved, signed, broadcast — is cryptographically attributed and stored. Non-repudiation by construction. Auditors and regulators read the same logs your ops team does.

Cryptographic provenance

Every decision is signed by the identity that made it. Service account or human, the chain of custody is unbroken and verifiable.

Full activity history

Filter by user, wallet, policy, contract, date. Export to CSV. Stream to your SIEM. Query through the API. The audit trail lives where you need it.

Compliance-ready

SOC2, ISO 27001. The audit trail satisfies internal and external review. No reconstruction, no excuses, no Excel exports.

Wallets dashboard

Discover how Nilos runs operations on DFNS.

“As a regulated custodian committed to the highest standards of compliance, our partnership with DFNS has been crucial. Their security best practices, programmatic developer tools, and robust infrastructure help us carry out carefully controlled operations. We also appreciate their team as they provide responsive support and sub-hour troubleshooting.”

Maker, checker, watcher

Service accounts handle the routine. Humans handle the exceptions. DFNS tracks everything that happens in-between.

Events to actions

Every onchain or platform state change fires a signed webhook. Every webhook drives a workflow. No polling, no miss.

Programmable in TypeScript

No DSL to learn. Decode any ABI, call any HTTP API, query any database, post any decision. The runtime is your stack.

Audited end to end

Every action, every approval, every API call, cryptographically signed and logged. Non-repudiation without paperwork.

Raphaël Fettaya CEO, Nilos

Four steps to a workflow that runs itself

Provision a service account. Subscribe to the events that matter. Codify the decisions. Audit everything. Production-ready in days.

Spin up a service account, scoped to one job.

A machine identity with the narrowest permission set that does the job. One service account per workflow. One per environment. One per failure radius.

// Create a scoped service account for your settlement workflow
const checker = await dfnsApi.auth.createServiceAccount({
  body: {
    name: "settlement-checker-prod",
    publicKey: "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
    permissionId: "pm-settlement-checker-v1",  // approve-only, no broadcast
    daysValid: 365
  }
});

// checker.id, checker.accessToken — credentials go to your secret store
// This identity can read pending approvals and post decisions. Nothing else.
Treat service accounts like microservices. One job, one identity. Scope permissions to the minimum that lets the workflow do its work. Rotate keys on a calendar.

Wire webhooks to the events that drive the workflow.

Subscribe once to the events that matter. DFNS delivers them signed and idempotent. Your handler is whatever you want it to be — a Lambda, a worker, a cron job, an Express endpoint.

// React to every event that matters to settlement
await dfnsApi.webhooks.createWebhook({
  body: {
    url: "https://workflows.yourbank.com/dfns/events",
    events: [
      "policy.approval.pending",           // a transaction needs a decision
      "wallets.transfer.confirmed",        // settlement landed, post to ledger
      "wallets.transfer.failed",           // settlement failed, escalate
      "wallets.transaction.broadcasted"    // broadcast confirmed, update CRM
    ]
  }
});

// Webhooks are signed (verify the X-Dfns-Signature header) and idempotent
// Deduplicate on deliveryId — at-least-once, never less
Verify the webhook signature on every payload. Deduplicate on deliveryId. Acknowledge fast (return 2xx) and process async. Slow handlers cause retries you don't want.

Codify the business rules. Approve, reject, or abstain.

Service accounts read the pending approval, decode the call data, run your rules, and post a decision. Approve when sure. Reject when malicious. Abstain when uncertain — humans take it from there.

// On 'policy.approval.pending' — your handler runs
async function onApprovalPending(event) {
  const approval = await dfnsApi.policies.getApproval({ approvalId: event.approvalId });
  const { to, data } = approval.activity.transactionRequest.requestBody;

  // Always validate the contract is in your allowlist BEFORE decoding
  if (!CONTRACT_ALLOWLIST.has(to.toLowerCase())) {
    return abstain(approval.id);  // human reviews, don't auto-reject
  }

  const decoded = decodeFunctionData({ abi, data });

  if (decoded.functionName === "mint") {
    const [recipient, amount] = decoded.args;
    const sanctionsHit  = await sanctions.check(recipient);           // any API
    const dailyMinted   = await ledger.getMintedToday(approval.activity.walletId);

    if (sanctionsHit)                          return reject(approval.id, "Sanctions match");
    if (amount > MAX_PER_TX)                   return abstain(approval.id);  // escalate
    if (dailyMinted + amount > DAILY_CAP)      return abstain(approval.id);

    return approve(approval.id, "Mint within policy");
  }

  return abstain(approval.id);  // unknown function, human decides
}
Pin the ABI to a trusted contract allowlist before decoding. Prefer abstaining over rejecting when uncertain — rejections are final, abstentions defer to humans in the same group. Reject only on unambiguous threats.

Review, export, prove.

Every decision is signed by the identity that made it. Every event is queryable. Pull last month's decisions in one call. Stream them into your SIEM. Hand them to your auditor without screenshots.

// Every decision is signed and queryable
const decisions = await dfnsApi.policies.listApprovalDecisions({
  query: {
    approverId: "sa-settlement-checker-prod-...",
    dateFrom: "2026-05-01",
    dateTo: "2026-05-31"
  }
});

// decisions.items[i] — id, approvalId, decision, reason, signature, timestamp
// Pipe to your audit warehouse, your SIEM, your monthly compliance report
// Verify signatures end to end if you need to prove provenance independently
Track approval latency, escalation rate, and false-positive rate. If the checker escalates too often, the rules are too tight. If it never escalates, the checks aren't thorough enough. Tune like any other production system.
Org → Service Accounts → New → Permission Set + Public Key
Org → Service Accounts → New → Permission Set + Public Key
Settings → Webhooks → New Endpoint → Subscribe to Events
Settings → Webhooks → New Endpoint → Subscribe to Events
Activity → Approvals → Filter by Approver: Service Account → Decisions
Activity → Approvals → Filter by Approver: Service Account → Decisions
Activity → Filter by Identity / Wallet / Date → Export CSV / Stream
Activity → Filter by Identity / Wallet / Date → Export CSV / Stream

Ready to see DFNS in action?

The new core for every fintech and institution going onchain.

Documentation

APIs, SDKs, and guides for builders.

Pricing

Per-transaction pricing, no hidden fees.

Contact us