Skip to main content
The SDK provides utilities for handling webhooks sent from the Corsa API.
import express from 'express';
import {
  WebhookEvent,
  WebhookEventType,
  WebhookSignatureHeader,
  verifyWebhookSignature
} from '@corsa-labs/sdk';
import dotenv from 'dotenv';

dotenv.config();

const app = express();

app.use('/webhook', express.raw({ type: 'application/json' }));

const WEBHOOK_SECRET = process.env.COMPLIANCE_SDK_WEBHOOK_SECRET;

app.post('/webhook', (req: express.Request, res: express.Response) => {
  const signature = req.headers[WebhookSignatureHeader] as string;
  const rawBody = req.body as Buffer;

  if (!WEBHOOK_SECRET) {
    console.error('Webhook secret is not configured.');
    return res.status(500).send('Webhook secret not configured.');
  }

  if (!signature) {
    console.warn('Missing signature header');
    return res.status(400).send('Missing signature header.');
  }

  try {
    const isValid = verifyWebhookSignature(
      WEBHOOK_SECRET,
      rawBody.toString('utf-8'),
      signature
    );
    if (!isValid) {
      return res.status(403).send('Invalid signature.');
    }
  } catch (error) {
    console.error('Invalid signature:', error);
    return res.status(403).send('Invalid signature.');
  }

  let event: WebhookEvent<unknown, unknown>;

  try {
    event = JSON.parse(rawBody.toString('utf-8'));
  } catch (error) {
    console.error('Error parsing webhook JSON:', error);
    return res.status(400).send('Invalid JSON payload.');
  }

  console.log(`Received webhook event: ${event.type}`);
  console.log(`Timestamp: ${event.timestamp}`);
  console.log('Data:', JSON.stringify(event.data, null, 2));

  switch (event.type) {
    case WebhookEventType.INDIVIDUAL_CLIENT_CREATED:
    case WebhookEventType.INDIVIDUAL_CLIENT_UPDATED:
    case WebhookEventType.CORPORATE_CLIENT_CREATED:
    case WebhookEventType.CORPORATE_CLIENT_UPDATED:
    case WebhookEventType.ALERT_CREATED:
    case WebhookEventType.ALERT_UPDATED:
    case WebhookEventType.CASE_CREATED:
    case WebhookEventType.CASE_UPDATED:
      console.log(`Handling ${event.type}...`);
      break;
    default:
      console.warn(`Unhandled event type: ${event.type}`);
  }

  res.status(200).send('Webhook received');
});

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Webhook handler listening on port ${PORT}`);
});

export default app;

Available Webhook Headers

ConstantHeaderDescription
WebhookSignatureHeaderx-hub-signature-256HMAC SHA256 signature for verification.
WebhookIdHeaderx-hook-idUnique ID of the webhook configuration.
WebhookDeliveryIdHeaderx-hook-deliveryUnique ID for this delivery attempt.
WebhookEventTypeHeaderx-hook-eventThe event type that triggered the webhook.
WebhookRequestIdHeaderx-request-idRequest trace ID.
WebhookRequestOriginHeaderx-request-originOrigin of the request.

Typed Event Helpers

The SDK exports typed event interfaces for each webhook event:
TypeEvent
IndividualClientCreatedEventIndividual client created
IndividualClientUpdatedEventIndividual client updated
CorporateClientCreatedEventCorporate client created
CorporateClientUpdatedEventCorporate client updated
AlertCreatedEventAlert created
AlertUpdatedEventAlert updated