Back to Guides
Pulse2Pay TeamJanuary 10, 20253 min read

Webhook Security: Signatures, Retries, and Idempotency

Secure your payment integration with HMAC signature verification, replay attack prevention, and idempotent processing.

Webhooks are the backbone of real-time payment notifications. This guide covers how to secure your webhook endpoint and handle notifications reliably.

Understanding Webhook Signatures

Every webhook from Pulse2Pay includes two security headers:

HeaderDescription

|--------|-------------|

X-Pulse2Pay-SignatureHMAC-SHA256 signature of the request X-Pulse2Pay-TimestampUnix timestamp (milliseconds) when the request was sent

Signature Verification

Important: Webhook signatures use a different format than API request signatures!

// API Signature (for your requests to Pulse2Pay):

HMAC-SHA256(api_secret, timestamp + "." + method + "." + path + "." + body)

// Webhook Signature (for Pulse2Pay's requests to you):

HMAC-SHA256(webhook_secret, timestamp + "." + body)

The webhook secret is provided when you register a webhook endpoint.

Example Implementation (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(req, webhookSecret) {

const signature = req.headers['x-pulse2pay-signature'];

const timestamp = req.headers['x-pulse2pay-timestamp'];

// Use raw body for accurate signature verification

const body = req.rawBody || JSON.stringify(req.body);

// Verify timestamp is within 5 minutes (timestamp is in milliseconds)

const now = Date.now();

if (Math.abs(now - parseInt(timestamp)) > 300000) {

throw new Error('Timestamp too old - possible replay attack');

}

// Compute expected signature (webhook format: timestamp.body)

const payload = ${timestamp}.${body};

const expected = crypto

.createHmac('sha256', webhookSecret)

.update(payload)

.digest('hex');

// Constant-time comparison

if (!crypto.timingSafeEqual(

Buffer.from(signature),

Buffer.from(expected)

)) {

throw new Error('Invalid signature');

}

return true;

}

Replay Attack Prevention

Always verify the timestamp:

  • Parse the X-Timestamp header
  • Compare with current server time
  • Reject requests older than 5 minutes
  • Consider tracking processed timestamps to prevent exact replays
  • Retry Logic

    Pulse2Pay retries failed webhooks with exponential backoff:

    AttemptDelay

    |---------|-------|

    1Immediate 21 second 35 seconds 430 seconds 51 minute 65 minutes

    A webhook is considered successful if your server returns a 2xx status code within 30 seconds. After 5 failed retry attempts, the webhook will be marked as failed.

    Idempotent Processing

    Your webhook handler must be idempotent. The same webhook may be delivered multiple times due to:

  • Network issues
  • Timeout retries
  • System failovers
  • Idempotency Best Practices

    async function handlePaymentWebhook(payment) {
    

    // Use the payment ID as an idempotency key

    const existing = await db.getPayment(payment.id);

    if (existing && existing.status === payment.status) {

    // Already processed - return success

    return { success: true, duplicate: true };

    }

    // Process the payment

    await db.updatePayment(payment.id, {

    status: payment.status,

    tx_hash: payment.tx_hash,

    processed_at: new Date()

    });

    return { success: true };

    }

    Webhook Events

    EventDescription

    |-------|-------------|

    payment.createdPayment request was created payment.pendingPayment is awaiting confirmation payment.confirmedPayment confirmed on blockchain payment.underpaidReceived amount was less than expected payment.overpaidReceived amount was more than expected payment.expiredPayment deadline passed payment.failedPayment processing failed payment.canceledPayment was canceled

    Testing Webhooks

    Use our sandbox environment to test webhooks before going live:

  • Set your webhook URL in the dashboard
  • Create test payments
  • Verify signature handling
  • Test error scenarios
  • Related Resources

  • Accept USDT Payments
  • API Reference
  • Developer Documentation
  • #webhooks#security#hmac#idempotency

    Ready to get started?

    Create your merchant account and start accepting crypto payments today.