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}`);
}
}
}