Get real-time updates using webhooks
Set up webhooks on your CryptoSwift account
CryptoSwift uses webhooks to notify your application when events such as Incoming Travel Rule Transaction or Self-Hosted Wallet Verification occurs.
Webhooks are useful if you want to create a full integration between CryptoSwift and your own application and collect Incoming Travel Rule Transaction or Self-Hosted Wallets Verification messages.
Building with an AI coding agent? See AI Agent Integration and AI Agent Prompts.
How webhooks are used by CryptoSwift
Webhooks enable CryptoSwift to push real-time notifications to your application. CryptoSwift uses a JSON payload that is sent over HTTPS to notify your application. Those notifications can be used to execute actions in your backend systems.
Receiving webhook notifications
You can start receiving event notifications in your app using the steps in this section:
- Create a webhook endpoint in your application
- Register the webhook URL in CryptoSwift
- Handle requests from CryptoSwift
- Secure your webhook endpoint
1. Create a webhook
Create a webhook endpoint on your server that will accept incoming data. Make sure the URL is publicly accessible once deployed. If you want to limit access to your webhook endpoint, make sure to whitelist the CryptoSwift API IPs that will be calling it:
- Dev: 34.88.32.82
- Prod: 35.228.164.60
2. Register your webhook URL
Once the webhook endpoint has been created, register the webhook public URL for your CryptoSwift account using the API or Client Dashboard (under Settings).
You can use the tenant/me PATCH endpoint and provide {"webhookUrl": "..."} object in the request body.
Notabene network webhooks
If you also want to receive Travel Rule messages from the Notabene network, configure Notabene to forward notifications to the tenant-specific URL shown in Client Dashboard → Settings → External integrations:
- Create a free Notabene account.
- Set the Notification Webhook URL in Notabene to the tenant-specific URL from the CryptoSwift dashboard.
3. Handle requests from CryptoSwift
CryptoSwift uses a JSON payload to notify your application.
There are multiple event types CryptoSwift can forward to your application which you can distinguish by checking the X-Event-Type header:
| Event Type | Header | Description |
|---|---|---|
| Travel Rule Transaction | transaction | For Travel Rule Transaction messages (new incoming transactions or status updates to existing outgoing transactions), the full Travel Rule message is forwarded to your application. See the Travel Rule data model for more details. |
| Self-hosted wallet verification | wallet-verification | For widget and API-driven verification updates. See the wallet verification widget and wallet verification API guides for payload details. |
Travel Rule messages
CryptoSwift sends a transaction event in two main situations:
- Incoming messages: expect a webhook when another VASP sends your tenant a Travel Rule message. The payload has
direction: "INCOMING"and normally starts withstatus: "DELIVERED". Further notifications can arrive when the originator adds or changes data. For example, adding thetransactionHashafter a pre-transaction message, or cancelling the message. - Outgoing updates: after you create an outgoing message, expect webhooks when its delivery or counterparty response changes. Common updates include delivery to the beneficiary VASP and the beneficiary confirming or declining the message. Beneficiary identification, risk analysis, and other processing can also add or update transaction data.
Each notification contains the full current Travel Rule message, not only the fields that changed. Reconcile it by id and use direction to route it to your incoming or outgoing workflow. In particular, inspect:
statusandstatusReasoningfor the current lifecycle state and any explanationblockchainInfofor the transaction hash, network, and wallet addressesvaspInfo,originator, andbeneficiaryfor counterparty or party-data changesriskScore, including sanctions results, pluswarningsandruleEnginewhen present
Some personal data can be omitted from incoming messages until the destination wallet is confirmed. For the disclosure rules, see PII data handling.
Example outgoing status-update payload:
{
"id": "233e3fd4-2ef0-477c-a398-8f993d131a19",
"status": "CONFIRMED",
"statusReasoning": null,
"direction": "OUTGOING",
"createdAt": "2026-07-31T09:42:18.519Z",
"asset": "ETH",
"amount": 0.059625001,
"amountUsd": 223.41,
"amountEur": 193.64,
"metadata": "withdrawal-8472",
"blockchainInfo": {
"transactionHash": "8129df36bf862c55702ab3991c4cc6d00903dc7af4b6f1afc909c216f07e34bd",
"origin": "0x1234567890abcdef1234567890abcdef12345678",
"destination": "0xabcdef1234567890abcdef1234567890abcdef12",
"destinationType": "CUSTODIAL",
"blockchain": "Ethereum",
"isDestinationConfirmed": true,
"destinationWalletId": 7069
},
"vaspInfo": {
"originatorVaspName": "Originator VASP",
"originatorVaspEmail": "support@originator.example",
"beneficiaryVaspName": "Beneficiary VASP",
"beneficiaryVaspEmail": "support@beneficiary.example",
"beneficiaryVaspExtraInfo": null
},
"originator": {
"type": "NATURAL",
"name": "Diana DueDiligence",
"accountNumber": "customer-123",
"address": "873 Audit Alley",
"country": "AU",
"nationalIdentificatorType": null,
"nationalIdentificator": null,
"customerNumber": "customer-123",
"dateOfBirth": null,
"placeOfBirth": null
},
"beneficiary": {
"type": "NATURAL",
"name": "John Smither",
"accountNumber": "AC-123",
"country": "EE",
"nationalIdentificatorType": null,
"nationalIdentificator": null
},
"travelRuleMessageSource": "CryptoSwift",
"riskScore": {
"originatorRiskScore": 18,
"originatorRiskSeverity": "low",
"beneficiaryRiskScore": 12,
"beneficiaryRiskSeverity": "low",
"sanctions": {
"originatorWallet": {
"isSanctioned": false,
"details": []
},
"beneficiaryWallet": {
"isSanctioned": false,
"details": []
}
}
},
"ruleEngine": {
"decision": "PROCEED",
"ruleEngineId": "6292e827-ce05-4cae-a3c8-43e1fb073e1e",
"ruleId": "7f3db7f7-b5b4-4dd7-8de6-e6c15a6eb9e2",
"ruleName": "Proceed with low-risk outgoing transfer",
"conditions": {
"all": [
{
"field": "beneficiaryRiskSeverity",
"operator": "EQ",
"value": "low"
}
],
"any": []
},
"ruleEngineVersion": 3,
"scope": "OUTGOING",
"waitForSeconds": null,
"onTimeoutDecision": null
}
}
Fields that are not available or do not apply can be null or omitted. Treat webhook deliveries as notifications: process them idempotently and retrieve the latest transaction with GET /transactions/{id} before making an irreversible decision.
Self-hosted wallet verifications
CryptoSwift sends a wallet-verification event when a wallet verification is updated or processed, whether the flow was started through the widget or the API. Notifications can follow proof submission, asynchronous Satoshi Test monitoring, or a manual status update.
Use id to reconcile the notification with your request. Inspect status and statusReasoning for the result, flow and metadata for routing, and the proof-specific, risk, warning, or reuse fields when present. Handle PENDING, VERIFIED, ACTION_REQUIRED, FAILED, DECLINED, and DELETED as current states rather than assuming every notification is a successful completion. The full payload and a current example are documented in Receive Notification via Webhook.
For both event types, verify the signature, parse the JSON body, queue any longer-running processing, and return a 2xx response.
4. Secure your webhook endpoint
Use webhook signatures to verify that it was indeed CryptoSwift that generated a webhook request and that it didn't come from a server acting like CryptoSwift. This is an optional but recommended step in order to guarantee a secure integration.
The custom CryptoSwift-Signature header is sent with each webhook notification. See webhook signatures to find out how to set up and validate webhook signatures.