Implementation

Code examples and best practices for implementing webhook handlers

Framework Examples

Choose your preferred framework to get started:

import express from 'express';
import crypto from 'crypto';
import { WebhookHandler } from './handlers';

const app = express();

// Parse raw body for signature verification
app.use(express.json({
  verify: (req: any, res, buf) => {
    req.rawBody = buf;
  }
}));

app.post('/webhooks', async (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const webhookSecret = process.env.WEBHOOK_SECRET;
  
  // Verify signature
  const hmac = crypto.createHmac('sha256', webhookSecret);
  const computedSignature = hmac
    .update(req.rawBody)
    .digest('hex');
  
  if (!crypto.timingSafeEqual(
    Buffer.from(computedSignature, 'hex'),
    Buffer.from(signature, 'hex')
  )) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Process event asynchronously
  const event = req.body;
  
  try {
    // Acknowledge receipt quickly
    res.status(200).json({ received: true });
    
    // Process in background
    await WebhookHandler.processEvent(event);
  } catch (error) {
    console.error('Webhook processing error:', error);
  }
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

Event Handler Example

Here's an example of handling payment events:

class WebhookHandler {
  static async processEvent(event: WebhookEvent) {
    switch (event.type) {
      case 'subscription.created':
        await this.handleSubscriptionCreated(event.data);
        break;
      case 'subscription.updated':
        await this.handleSubscriptionUpdated(event.data);
        break;
      case 'transaction.created':
        await this.handleTransactionCreated(event.data);
        break;
      case 'transaction.updated':
        await this.handleTransactionUpdated(event.data);
        break;
      default:
        console.log(`Unhandled event type: ${event.type}`);
    }
  }

  static async handleSubscriptionCreated(data: SubscriptionData) {
    // Update user's subscription status
    await db.subscriptions.create({
      userId: data.customerId,
      planId: data.planId,
      status: data.status,
      currentPeriodEnd: data.currentPeriodEnd
    });
  }

  // ... implement other handlers
}

Last updated