Skip to main content
Webhooks let Thiqwave push event notifications to your server the moment something happens — a transaction completes, a KYB check passes, or a new account is created. Instead of repeatedly polling the API for status updates, you receive an HTTP POST to your endpoint with the event payload.

Available events

EventWhen it fires
settlement.convertingSettlement fiat-to-stablecoin conversion started
settlement.transmittingStablecoin in transit on-chain
settlement.completedSettlement completed, destination credited
settlement.failedSettlement failed
payin.completedA pay-in has been received and confirmed
payout.completedA payout has been delivered
payout.failedA payout failed
compliance.approvedA KYB submission has been approved.
compliance.rejectedA KYB submission was rejected.
account.createdA new account was created.
account.fundedFunds arrived at an account.

Set up a webhook endpoint

1

Create a public HTTPS endpoint

Your endpoint must:
  • Accept POST requests
  • Be reachable over the public internet via HTTPS
  • Return a 2xx status code within 10 seconds to acknowledge receipt
Any response outside the 2xx range — or no response within 10 seconds — is treated as a delivery failure and triggers the retry policy.
During development, use a tool like ngrok or Hookdeck to expose a local server for testing.
2

Register your endpoint in the dashboard

  1. Log in to the Thiqwave Dashboard.
  2. Navigate to Settings → Webhooks.
  3. Click Add endpoint.
  4. Enter your endpoint URL.
  5. Select the events you want to receive (or choose All events).
  6. Click Save.
Thiqwave generates a webhook secret for the endpoint. Copy and store it securely — you use it to verify incoming payloads.
3

Verify webhook signatures

Every webhook request includes a X-Thiqwave-Signature header. Verify this signature before processing the payload to ensure it came from Thiqwave and was not tampered with.The signature is an HMAC-SHA256 hex digest of the raw request body, computed using your webhook secret as the key.
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, webhookSecret) {
  const expectedSignature = crypto
    .createHmac('sha256', webhookSecret)
    .update(rawBody)
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  const expected = Buffer.from(expectedSignature, 'hex');
  const received = Buffer.from(signature, 'hex');

  if (expected.length !== received.length) {
    return false;
  }

  return crypto.timingSafeEqual(expected, received);
}

// Express.js example
app.post('/webhooks/thiqwave', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-thiqwave-signature'];
  const webhookSecret = process.env.THIQWAVE_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, webhookSecret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const event = JSON.parse(req.body);
  console.log('Received event:', event.event, event.data.id);

  // Process the event...

  res.status(200).json({ received: true });
});
Always parse the raw request body before parsing as JSON when computing the signature. If you parse JSON first and re-serialise, byte-level differences will cause signature verification to fail.
4

Process the event payload

After verifying the signature, parse the JSON body and handle the event based on the event field:
{
  "event": "payout.completed",
  "id": "evt_01HXYZEVT1234567890AB",
  "timestamp": "2026-04-08T10:05:23Z",
  "signature": "a3f1c2d4e5b6...",
  "data": {
    "id": "payout_01HXYZABCDEF1234567890",
    "type": "payout",
    "status": "completed",
    "amount": 500000,
    "currency": "SAR",
    "recipient": {
      "account_number": "123456789012",
      "bank_code": "050"
    },
    "completed_at": "2026-04-08T10:05:20Z"
  }
}
FieldTypeDescription
eventstringThe event type (e.g., transaction.completed).
idstringUnique identifier for this event delivery.
timestampstringISO 8601 timestamp of when the event occurred.
signaturestringHMAC-SHA256 signature for verification (also in the header).
dataobjectThe full resource object that triggered the event.
Respond with a 2xx status as quickly as possible. Move any slow processing (database writes, downstream API calls) to a background job to avoid timeouts.

Retry policy

If your endpoint does not return a 2xx response within 10 seconds, Thiqwave retries the delivery with exponential backoff:
AttemptDelay
1st retry1 minute
2nd retry10 minutes
3rd retry1 hour
After 3 failed retries, the delivery is marked as failed. You can view failed deliveries and manually replay them in the dashboard under Settings → Webhooks → Delivery logs.
Make your webhook handler idempotent. Because retries can deliver the same event more than once, use the id field to deduplicate events before processing them.

Testing webhooks

Use the Send test event button in the dashboard to fire a sample payload to your endpoint at any time. This lets you verify your handler logic without waiting for a real transaction. You can also replay any past delivery from Settings → Webhooks → Delivery logs, which is useful for debugging failed handlers.

Next steps