Skip to main content

Signature Validation

For security, all webhooks from Chipi Pay include an HMAC signature in the chipi-signature header. You should verify this signature to ensure the webhook is from Chipi Pay and hasn’t been tampered with.

Why Verify Signatures?

Always verify webhook signatures in production. This prevents unauthorized requests and ensures data integrity.
Webhook signature verification:
  • Prevents spoofing - Ensures requests are from Chipi Pay
  • Protects data integrity - Detects if payloads have been modified
  • Security best practice - Industry standard for webhook security

Getting Your Webhook Secret

  1. Go to your webhook configuration page in the Chipi Dashboard
  2. Copy your Webhook Signing Secret (it looks like whsec_****)
  3. Store it securely as an environment variable

Implementation

Step 1: Install Required Dependencies

npm install crypto

Step 2: Create a Signature Verification Function

import { createHmac, timingSafeEqual } from 'crypto';

function verifyWebhookSignature(
  payload: string,
  receivedSignature: string,
  secretKey: string
): boolean {
  try {
    const expectedSignature = createHmac("sha256", secretKey)
      .update(payload)
      .digest("hex");

    // Use timing-safe comparison to prevent timing attacks
    return timingSafeEqual(
      Buffer.from(expectedSignature, "hex"),
      Buffer.from(receivedSignature, "hex")
    );
  } catch (error) {
    return false;
  }
}

Step 3: Verify in Your Webhook Handler

// Example webhook handler (adjust based on your framework)
export async function POST(request: Request) {
  const payload = await request.text();
  const signature = request.headers.get('chipi-signature');
  const webhookSecret = process.env.CHIPI_WEBHOOK_SECRET!; // Your whsec_**** key

  if (!signature || !verifyWebhookSignature(payload, signature, webhookSecret)) {
    return new Response(
      JSON.stringify({ error: 'Invalid signature' }), 
      { status: 401 }
    );
  }

  const event = JSON.parse(payload);

  // Handle the webhook event
  if (event.event === 'transaction.sent' && event.data.transaction.status === 'SUCCESS') {
    // Handle successful payment
    const transaction = event.data.transaction;
    console.log(`Payment received: ${transaction.amount} USDC from ${transaction.senderAddress}`);
    
    // Update your database, send confirmation emails, fulfill orders, etc.
  }

  return new Response(JSON.stringify({ received: true }), { status: 200 });
}

Security Best Practices

  • Always use timing-safe comparison functions to prevent timing attacks
  • Store your webhook secret in environment variables, never in code
  • Verify signatures before processing any webhook data
  • Log failed signature verifications for security monitoring

Common Issues

Signature Mismatch

If you’re getting signature mismatches:
  1. Ensure you’re using the correct webhook secret from your dashboard
  2. Verify you’re reading the raw request body (not parsed JSON)
  3. Check that the chipi-signature header is being read correctly
  4. Make sure you’re using SHA-256 HMAC

Environment Variables

Store your webhook secret securely:
# .env
CHIPI_WEBHOOK_SECRET=whsec_your_secret_key_here

Next Steps