Skip to content

Webhook Integration Examples

Set up and handle webhook events from de.iterate.

Create Webhook Subscription

typescript
import { DeIterateClient } from '@deiterate/sdk';

const client = new DeIterateClient({
  apiKey: process.env.DEITERATE_API_KEY!,
  organizationId: process.env.DEITERATE_ORG_ID,
});

async function setupWebhook() {
  const webhook = await client.webhooks.create({
    url: 'https://your-app.com/webhooks/deiterate',
    events: [
      'risk.created',
      'risk.updated',
      'task.overdue',
      'document.expired',
      'audit.completed',
    ],
    secret: process.env.WEBHOOK_SECRET,
  });
  
  console.log(`Created webhook: ${webhook.id}`);
  
  // Test the webhook
  const result = await client.webhooks.test(webhook.id);
  if (result.success) {
    console.log('✅ Webhook test successful');
  } else {
    console.log(`❌ Webhook test failed: ${result.error}`);
  }
}

Express.js Webhook Handler

typescript
import express from 'express';
import crypto from 'crypto';
import { WebhookEvent, Risk, Task, Document } from '@deiterate/sdk';

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;

// Verify webhook signature
function verifySignature(payload: string, signature: string): boolean {
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Webhook endpoint
app.post('/webhooks/deiterate', (req, res) => {
  const signature = req.headers['x-deiterate-signature'] as string;
  const payload = JSON.stringify(req.body);
  
  if (!verifySignature(payload, signature)) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Invalid signature');
  }
  
  const event = req.body as WebhookEvent;
  
  // Process event asynchronously
  processEvent(event).catch(console.error);
  
  // Respond quickly
  res.status(200).send('OK');
});

async function processEvent(event: WebhookEvent) {
  console.log(`Processing event: ${event.type} (${event.id})`);
  
  switch (event.type) {
    case 'risk.created':
      await handleRiskCreated(event.data.object as Risk);
      break;
      
    case 'risk.updated':
      await handleRiskUpdated(
        event.data.object as Risk,
        event.data.previousAttributes as Partial<Risk>
      );
      break;
      
    case 'task.overdue':
      await handleTaskOverdue(event.data.object as Task);
      break;
      
    case 'document.expired':
      await handleDocumentExpired(event.data.object as Document);
      break;
      
    case 'audit.completed':
      await handleAuditCompleted(event);
      break;
      
    default:
      console.log(`Unhandled event type: ${event.type}`);
  }
}

async function handleRiskCreated(risk: Risk) {
  console.log(`New risk created: ${risk.risk}`);
  
  // Notify Slack
  await notifySlack({
    channel: '#security-alerts',
    text: `🆕 New Risk: ${risk.risk}`,
    blocks: [
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `*New Risk Created*\n${risk.risk}\n\nCategory: ${risk.riskCategory || 'N/A'}\nSeverity: ${risk.inherentRisk || 'N/A'}`,
        },
      },
    ],
  });
}

async function handleRiskUpdated(risk: Risk, changes: Partial<Risk>) {
  console.log(`Risk updated: ${risk.risk}`);
  console.log('Changed fields:', Object.keys(changes));
  
  // Check if severity increased
  if (changes.inherentRisk && risk.inherentRisk === 'High') {
    await notifySlack({
      channel: '#security-alerts',
      text: `⚠️ Risk escalated to High: ${risk.risk}`,
    });
  }
}

async function handleTaskOverdue(task: Task) {
  console.log(`Task overdue: ${task.description}`);
  
  // Send reminder email
  await sendEmail({
    to: task.assignedTo,
    subject: `Overdue: ${task.description}`,
    body: `Your task "${task.description}" is overdue. Please complete it as soon as possible.`,
  });
  
  // Notify manager
  await notifySlack({
    channel: '#compliance-alerts',
    text: `📋 Overdue Task: ${task.description} (assigned to ${task.assignedTo})`,
  });
}

async function handleDocumentExpired(doc: Document) {
  console.log(`Document expired: ${doc.fileName}`);
  
  await notifySlack({
    channel: '#document-reviews',
    text: `📄 Document Review Needed: ${doc.fileName}`,
  });
}

async function handleAuditCompleted(event: WebhookEvent) {
  console.log('Audit completed');
  
  await notifySlack({
    channel: '#compliance',
    text: `✅ Audit Completed`,
  });
}

// Stub functions
async function notifySlack(message: any) {
  console.log('Slack notification:', message);
}

async function sendEmail(email: any) {
  console.log('Email sent:', email);
}

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

Serverless Webhook Handler (AWS Lambda)

typescript
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import crypto from 'crypto';
import { WebhookEvent } from '@deiterate/sdk';

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;

export async function handler(
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> {
  const signature = event.headers['x-deiterate-signature'];
  const payload = event.body || '';
  
  // Verify signature
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (signature !== expected) {
    return {
      statusCode: 401,
      body: 'Invalid signature',
    };
  }
  
  const webhookEvent = JSON.parse(payload) as WebhookEvent;
  
  // Process the event
  await processEvent(webhookEvent);
  
  return {
    statusCode: 200,
    body: 'OK',
  };
}

async function processEvent(event: WebhookEvent) {
  // Store in DynamoDB, trigger Step Functions, etc.
  console.log(`Processing: ${event.type}`);
}

Manage Webhooks

typescript
async function manageWebhooks() {
  // List all webhooks
  const webhooks = await client.webhooks.list();
  console.log(`Found ${webhooks.length} webhooks\n`);
  
  for (const webhook of webhooks) {
    console.log(`ID: ${webhook.id}`);
    console.log(`URL: ${webhook.url}`);
    console.log(`Events: ${webhook.events.join(', ')}`);
    console.log(`Active: ${webhook.active}`);
    console.log();
  }
  
  // Disable a webhook
  const webhookId = webhooks[0]?.id;
  if (webhookId) {
    await client.webhooks.update(webhookId, { active: false });
    console.log(`Disabled webhook: ${webhookId}`);
  }
  
  // Delete old webhooks
  for (const webhook of webhooks) {
    if (!webhook.active) {
      await client.webhooks.delete(webhook.id);
      console.log(`Deleted inactive webhook: ${webhook.id}`);
    }
  }
}

Released under the MIT License.