Skip to content

Webhooks & Status Synchronization

Verify Partner webhook signatures and process privacy-preserving status updates.

CryptoSwift sends Partner webhook notifications when a supported Partner-originated Travel Rule transaction is updated. This is mainly used for status updates, for example when a CryptoSwift client confirms or declines a Partner -> CryptoSwift Travel Rule message.

Partner webhook updates intentionally strip personal details to preserve privacy boundaries. They do not include IVMS101 data or other personal data. The payload carries transaction metadata and state tags such as PENDING, DELIVERED, CONFIRMED, DECLINED, and FAILED.

Enable Partner Webhooks

Set webhookUrl using PATCH /partners/me. CryptoSwift generates a webhookSecret, which you retrieve with GET /partners/me.

Refresh the webhook secret after URL changes

When webhookUrl is updated, CryptoSwift automatically generates a new webhookSecret. Call GET /partners/me immediately after updating the webhook URL and store the new secret for signature verification.

Webhook Request

CryptoSwift sends an HTTP POST request to the configured webhookUrl.

Headers:

X-Event-Type: transaction
CryptoSwift-Signature: t=<timestamp>,s=<signature>

The CryptoSwift-Signature header is generated using HMAC SHA-256 over the timestamp and raw body payload:

payload_to_sign = <timestamp> + "." + <raw JSON request body>
signature = HMAC-SHA256(payload_to_sign, webhookSecret)

The timestamp is included in the t value and the hex-encoded signature is included in the s value.

Webhook Payload

{
  "id": "86cc6fd8-caac-4b13-bb84-5d58e5d6d0cc",
  "status": "CONFIRMED",
  "statusReasoning": "Confirmed by beneficiary",
  "asset": "BTC",
  "amount": 0.1,
  "blockchainInfo": {
    "transactionHash": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
    "origin": "origin-wallet-address",
    "destination": "destination-wallet-address",
    "destinationType": "CUSTODIAL",
    "blockchain": "Bitcoin"
  },
  "createdAt": "2026-06-02T10:00:00.000Z"
}

Use the id field to match the notification to the Travel Rule transaction previously created through the Partner integration. Process status updates idempotently because delivery retries can occur.

Testing

To test Partner webhook notifications in the Test environment, send Partner Travel Rule messages to the known responding sandbox wallets listed in the Testing webhook notifications guide.

That guide lists wallet addresses, assets, blockchains, and expected response behavior. It does not list the Partner beneficiary VASP IDs directly. Use GET /partners/vasps/by-wallet with the test wallet address, blockchain, and asset to resolve the matching beneficiary VASP and retrieve the public key needed for encryption. Then send your POST /partners/transactions request to that resolved VASP.

When the sandbox beneficiary VASP responds, CryptoSwift sends a Partner webhook notification to your configured webhookUrl. Matching test data should produce a CONFIRMED update; intentionally mismatched beneficiary data can produce a DECLINED update, depending on the test wallet scenario.

Verify the Signature

Verify the CryptoSwift-Signature header before processing the webhook. The verifier must use the raw request body exactly as received, before JSON parsing or formatting.

const crypto = require('crypto');

function verifyCryptoSwiftSignature(rawBody, signatureHeader, webhookSecret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.split('='))
  );

  const timestamp = parts.t;
  const receivedSignature = parts.s;

  const payloadToSign = `${timestamp}.${rawBody}`;
  const expectedSignature = crypto
    .createHmac('sha256', webhookSecret)
    .update(payloadToSign)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(receivedSignature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  );
}

It is also recommended to reject old timestamps according to your replay-protection policy.