Skip to main content
When an event occurs in the system which a Webhook is subscribed to, we create a Webhook Event object containing data around the event that happened. We then:
  1. Send the event to your Webhook endpoint
  2. Capture a trace of the event so you can later check all Webhook Events sent to your webhooks (through List Webhook Events or Get Webhook Event endpoints)
We only keep a trace of Webhook Events in our system for a retention period of 31 days. Past that, they are discarded, so you cannot see them using List Webhook Events or Get Webhook Event endpoints.
Here’s an example of a Webhook Event of kind “wallet.transfer.requested” delivered to your webhook:
{
  "id": "wh-xxx-xxxxxxx",
  "kind": "wallet.transfer.requested",
  "date": "2023-12-04T10:02:22.280Z",
  "data": {
    "transferRequest": {
      "id": "xfr-1vs8g-c1ub1-xxxxxxxxxxxxxxxx",
      "walletId": "wa-39abb-e9kpk-xxxxxxxxxxxxxxxx",
      "network": "EthereumSepolia",
      "requester": {
        "userId": "us-3v1ag-v6b36-xxxxxxxxxxxxxxxx",
        "tokenId": "to-7mkkj-c831n-xxxxxxxxxxxxxxxx",
       },
      "requestBody": {
        "kind": "Native",
        "to": "0xb282dc7cde21717f18337a596e91ded00b79b25f",
        "amount": "1000000000"
      },
      "dateRequested": "2023-05-08T19:14:25.568Z",
      "status": "Pending"
    }
  },
  "status": "200",
  "timestampSent": 1701684144,
}

Supported Webhook Events

The list below shows which event kinds webhooks can subscribe to ⬇️ (see Webhook Event Data section for details on each event kind)
Event EnumDescription
wallet.blockchainevent.detectedA wallet event has been detected on chain (eg. a deposit). Note: This is only available for Tier-1 chains.
wallet.createdA wallet has been created.
wallet.exportedA wallet has been exported.
wallet.delegatedA wallet has been delegated.
wallet.signature.requestedA generate signature request has been created.
wallet.signature.failedA generate signature request has failed to process.
wallet.signature.rejectedA generate signature request with a policy approval has been rejected.
wallet.signature.signedA generate signature request has completed.
wallet.transaction.requestedA broadcast transaction request has been created.
wallet.transaction.failedA broadcast transaction request has failed to process.
wallet.transaction.rejectedA broadcast transaction request with a policy approval has been rejected.
wallet.transaction.broadcastedA broadcast transaction request has been submitted to the mempool.
wallet.transaction.confirmedA broadcast transaction request has been confirmed on chain. Note: This is only available for Tier-1 chains.
wallet.transfer.requestedA wallet transfer request has been created.
wallet.transfer.failedA wallet transfer request has failed to process.
wallet.transfer.rejectedA wallet transfer request with a policy approval has been rejected.
wallet.transfer.broadcastedA wallet transfer request has been submitted to the mempool.
wallet.transfer.confirmedA wallet transfer request has been confirmed on chain. Note: This is only available for Tier-1 chains.
policy.triggeredA policy got triggered upon some activity (the policy rule got evaluated, and it triggered)
policy.approval.pendingA new Approval process has been created and is pending.
policy.approval.resolvedA new Approval process is finalized: it’s either approved or rejected.

Webhook Event Data

Each webhook event has a “data” property, which shape depends on its kind. Here’s an overview of the shape of the data for each kind:
data
{ // Wallet object, as in "Create Wallet" endpoint response
  "wallet": {      
    "id": "wa-xxx-xxxxxxxxx",
    ...
  }
}
  • For wallet.transfer.requested, wallet.transfer.failed, wallet.transfer.rejected, wallet.transfer.broadcasted, wallet.transfer.confirmed see the Get Transfer response:
data
{ // Wallet Transfer Request object as in "Wallet Send Transfer" endpoint
  "transferRequest": {
    "id": "xfr-xxx-xxxxxxxxx",
    "walletId": "wa-xxx-xxxxxxxx",
    ...
  }
}
  • For wallet.transaction.requested, wallet.transaction.failed, wallet.transaction.rejected, wallet.transaction.broadcasted, wallet.transaction.confirmed see the Get Transaction response :
data
{ // Wallet Transaction Request as in "Wallet Broadcast Transaction" endpoint
  "transactionRequest": {
    "id": "tx-xxx-xxxxxxxxx",
    "walletId": "wa-xxx-xxxxxxxx",
    ...
  }
}
  • For wallet.signature.requested, wallet.signature.failed, wallet.signature.rejected, wallet.signature.signed see the Get Signature response:
data
{ // Wallet Signature Request object as in "Wallet Generate Signature" endpoint
  "signatureRequest": {
    "id": "sig-xxx-xxxxxxxxx",
    "walletId": "wa-xxx-xxxxxxxx",
    ...
  }
}
  • For wallet.blockchainevent.detected various event kinds are available depending on the indexed chain:\
KindChains
NativeTransferAll
Aip21TransferAptos
AsaTransferAlgorand
CoinTransfer, LockedCoinTransferIota
Erc20Transfer, Erc721TransferEvm
Tep74TransferTon
Trc10Transfer, Trc20Transfer, Trc721TransferTron
Sep41TransferStellar
SplTransfer, Spl2022TransferSolana
UtxoTransferBitcoin, Litecoin, Dogecoin, Kaspa
for example, see the Get History response:
data
{ // Blockchain Event object as in "Wallet Get Wallet History" endpoint
  "blockchainEvent": {
    "kind": "Erc20Transfer",
    "contract": "0x......",
    "from": "0x......",
    "to": "0x......",
    "direction": "In",
    ...
  }
}
  • For policy.triggered
data
{
  "policyEvaluation": {
    "id": "plce-xxxxxxx",
    "triggered": true,
    "reason": "Transfer amount (USD 10000) is above limit (USD 5000). ",
    "date": "2024-06-28T09:09:54.437Z",

    "policy": { // policy object as in "Get Policy" endpoint
      "id": "plc-xxxxxxx",
      "name": "Accounting wallet transfer limit",
      ...,
    },

    "activity": {
      "kind": "Wallets:Sign"
      "transferRequest": { // transfer request object as in "Get Transfer" endpoint
        "id": "xfr-xxxxxxx",
        ...
      }
    },

    "context": { // its content depends on the kind of the policy rule
      "transactionAmount": {
        "value": "10000,
        "currency": "USD",
      },
    },
  }
}
data
{ // Approval object
  "approval": {      
    "activityId": "cr-2100g-xxxxxxxxx",
    ...
  }
}

Webhook Event Ordering

Dfns doesn’t guarantee delivery of events in the order in which they’re generated. For example, when a wallet Transfer is picked up on-chain by our blockchain indexers, we might generate the following events:
  • wallet.transfer.confirmed - this event notifies you that the Transfer Request that you made has been confirmed on chain
  • wallet.blockchainevent.detected- this event notifies you of the new Blockchain Event detected and added to your Wallet History blockchain events
Your endpoint shouldn’t expect delivery of these events in this order, and needs to handle delivery accordingly.

Webhook Event Deliveries & Retries

During an webhook event delivery attempt, if we cannot reach your webhook endpoint, or if your endpoint returns anything else than a 200 status code in the response, we consider the delivery of this event has failed. In such a case, Dfns is going to retry delivering it to your webhook, up to 5 total attempts over 24 hours, with an exponential backoff (delays from first attempt: 1m, 12min, 2h, 1d). Every event delivery attempt will create a new Webhook Event, with its own unique ID, containing the same data than the previous event which failed delivering. So in the List Webhook Events endpoint, every Webhook Event you will see is a unique delivery attempt (potentially of the same original event). The event that your webhook handler will receive (in your server), will include the attempt number in the payload (deliveryAttempt: 1 for the first attempt). Also, if it includes the field retryOf: "whe-xxxxxxx" , it indicates that this event you are receiving, is a “retry of” a previous Webhook Event which failed delivering. Additionally, if you fetch Webhook Events we tried delivering, using the List Webhook Events or Get Webhook , you will be able to see the deliveryFailed boolean field indicating if delivery succeeded or not, as well as the nextAttemptDate: "2024-01-24-xxxxxx" date showing you around which time the next delivery attempt to your webhook will occur (if delivery failed). If you want to fetch all Webhook Events which failed delivering to your webhook, you can use the List Webhook Events with the query parameter deliveryFailed=true. And amongst all those returned, you can see those which failed delivering, and will not retry in future (because reached maximum retry attempt), by filtering those which have no nextAttemptDate . If your webhook has been disabled or deleted when Dfns attempts a retry, future retries of that event are prevented. However, if you disable and then re-enable a webhook endpoint before Dfns can retry, you can still expect to see future retry attempts.
I