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
- Go to your webhook configuration page in the Chipi Dashboard
- Copy your Webhook Signing Secret (it looks like
whsec_****)
- Store it securely as an environment variable
Implementation
Step 1: Install Required Dependencies
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:
- Ensure you’re using the correct webhook secret from your dashboard
- Verify you’re reading the raw request body (not parsed JSON)
- Check that the
chipi-signature header is being read correctly
- 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