Webhooks
Webhooks notify your systems when events occur.
Payment Webhooks
Section titled “Payment Webhooks”Stripe Webhook
Section titled “Stripe Webhook”POST /api/stripe-webhookHeaders:
Stripe-Signature: <signature>Content-Type: application/jsonEvents:
checkout.session.completed- Payment successfulpayment_intent.payment_failed- Payment failed
Example Payload:
{ "type": "checkout.session.completed", "data": { "object": { "id": "cs_abc123", "metadata": { "orderId": "order_xyz789" } } }}Billplz Webhook
Section titled “Billplz Webhook”POST /api/webhook/billplzFormat: URL-encoded
Parameters:
billplz[id]- Bill IDbillplz[paid]- true/falsebillplz[paid_at]- Timestamp
BayarCash Webhook
Section titled “BayarCash Webhook”POST /api/webhook/bayarcashPayload:
{ "payment_intent_id": "pi_123", "status": "completed", "transaction_id": "txn_456"}Chip Webhook
Section titled “Chip Webhook”POST /api/webhook/chipPayload:
{ "id": "purchase_123", "status": "paid", "payment": { "status": "captured" }}Webhook Security
Section titled “Webhook Security”All webhooks verify signatures:
- Gateway sends signature header
- Pintas computes expected signature
- Compares signatures
- Rejects if mismatch
Signature Verification Example
Section titled “Signature Verification Example”const crypto = require('crypto');
function verifyStripeSignature(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}Best Practices
Section titled “Best Practices”- Verify signatures - Always validate
- Respond quickly - Return 200 fast
- Handle duplicates - Webhooks may retry
- Log everything - Debug issues
- Use HTTPS - Required for production
Testing Webhooks
Section titled “Testing Webhooks”Stripe CLI
Section titled “Stripe CLI”stripe listen --forward-to localhost:3000/api/stripe-webhookngrok http 3000# Use: https://abc123.ngrok.io/api/stripe-webhookTroubleshooting
Section titled “Troubleshooting”| Issue | Solution |
|---|---|
| Signature error | Check secret matches |
| Timeout | Process async, respond fast |
| Not receiving | Verify URL and network |
| Duplicates | Track processed IDs |