const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
app.post('/webhooks/carbn', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const eventId = req.headers['x-webhook-event-id'];
const webhookId = req.headers['x-webhook-id'];
const payload = req.body;
// Verify webhook signature (recommended)
if (!verifySignature(JSON.stringify(payload), signature)) {
return res.status(401).send('Unauthorized');
}
// Handle idempotency using event ID
if (isEventProcessed(eventId)) {
return res.status(200).send('Already processed');
}
const { status, txn_id, user_id } = payload;
switch (status) {
case 'PAYMENT_PROCESSED':
handlePaymentProcessed(txn_id, user_id);
break;
case 'PAYMENT_FAILED':
handlePaymentFailed(txn_id, user_id);
break;
default:
console.log('Unknown payment status:', status);
}
// Mark event as processed
markEventProcessed(eventId);
res.status(200).send('OK');
});
function verifySignature(payload, signature) {
// Carbn uses RSA signature verification with base64 encoded signature
// This is a simplified example - implement proper RSA verification
const publicKey = process.env.CARBN_PUBLIC_KEY;
try {
const verify = crypto.createVerify('SHA256');
verify.update(payload);
const signatureBuffer = Buffer.from(signature, 'base64');
return verify.verify(publicKey, signatureBuffer);
} catch (error) {
console.error('Signature verification failed:', error);
return false;
}
}
function handlePaymentProcessed(txnId, userId) {
console.log(`Payment ${txnId} processed for user ${userId}`);
// Update your database, notify user, etc.
}
function handlePaymentFailed(txnId, userId) {
console.log(`Payment ${txnId} failed for user ${userId}`);
// Handle payment failure, notify user, etc.
}