GuidesAPI ReferenceChangelog
API Reference

Authentication

Signing secret

The webhook signing secret is the same secret key associated with your API key.

HTTP Headers

All webhook requests include the following headers:

HeaderDescriptionExample
Content-TypeRequest content typeapplication/json
X-Webhook-SignatureHMAC-SHA256 signaturea1b2c3d4e5f6... (64 chars)
X-Webhook-TimestampUnix timestamp (seconds)1705920000
X-Webhook-Event-IdUnique event ID12345
X-Webhook-Event-NameEvent typedeposit.completed
X-Webhook-Delivery-IdDelivery attempt ID67890

Signature Verification

To verify webhook authenticity, compute the HMAC-SHA256 signature and compare it with X-Webhook-Signature.

Algorithm

signed_payload = "{timestamp}.{request_body}"
expected_signature = HMAC-SHA256(signed_payload, webhook_secret)

Verification Steps

  1. Extract X-Webhook-Signature and X-Webhook-Timestamp from headers
  2. Concatenate: {timestamp}.{raw_request_body}
  3. Compute HMAC-SHA256 using your webhook secret
  4. Compare signatures using constant-time comparison
  5. Reject if timestamp is older than 5 minutes (replay attack prevention)

Code Example (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, timestamp, secret) {
  // Check timestamp (5 minute tolerance)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - timestamp) > 300) {
    return false;
  }

  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  // Constant-time comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Code Example (Python)

import hmac
import hashlib
import time

def verify_webhook_signature(payload: str, signature: str, timestamp: int, secret: str) -> bool:
    # Check timestamp (5 minute tolerance)
    now = int(time.time())
    if abs(now - timestamp) > 300:
        return False

    # Compute expected signature
    signed_payload = f"{timestamp}.{payload}"
    expected_signature = hmac.new(
        secret.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()

    # Constant-time comparison
    return hmac.compare_digest(signature, expected_signature)