Webhooks Overview
Webhooks Overview
Section titled “Webhooks Overview”LMIF webhooks notify your platform of events in real-time, allowing you to respond immediately to identity protection changes.
Why Use Webhooks?
Section titled “Why Use Webhooks?”Instead of polling the API, webhooks push events to you:
- Real-time: Know immediately when identities are boxed
- Efficient: No wasted API calls
- Reliable: Automatic retries on failure
- Secure: Signed payloads prevent tampering
Setting Up Webhooks
Section titled “Setting Up Webhooks”1. Register Your Endpoint
Section titled “1. Register Your Endpoint”const webhook = await lmif.webhooks.create({ url: 'https://yoursite.com/webhooks/lmif', events: ['box.created', 'grace_period.started', 'license.approved'], secret: 'your-webhook-secret' // Optional, we'll generate one if not provided});
console.log('Webhook secret:', webhook.secret);// Store this securely - you'll need it to verify signatures- Go to Settings → Webhooks
- Click Add Endpoint
- Enter your URL
- Select events to subscribe to
- Copy the generated secret
2. Handle Incoming Events
Section titled “2. Handle Incoming Events”import express from 'express';import { LMIFClient } from '@lookmaimfamous/lmif';
const app = express();const lmif = new LMIFClient({ apiKey: process.env.LMIF_API_KEY });
app.post('/webhooks/lmif', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-lmif-signature']; const payload = req.body;
// Verify signature if (!lmif.webhooks.verify(payload, signature, process.env.LMIF_WEBHOOK_SECRET)) { console.error('Invalid webhook signature'); return res.status(401).send('Invalid signature'); }
const event = JSON.parse(payload);
// Handle the event switch (event.type) { case 'box.created': handleBoxCreated(event.data); break; case 'grace_period.started': handleGracePeriodStarted(event.data); break; // ... handle other events }
// Acknowledge receipt res.status(200).send('OK');});3. Verify Signatures
Section titled “3. Verify Signatures”Always verify webhook signatures to ensure events are from LMIF:
// Using the SDKconst isValid = lmif.webhooks.verify(payload, signature, secret);
// Manual verificationimport crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean { const expectedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(`sha256=${expectedSignature}`) );}Webhook Payload Format
Section titled “Webhook Payload Format”All webhooks follow this format:
{ "id": "evt_abc123", "type": "box.created", "createdAt": "2024-01-15T10:00:00Z", "data": { // Event-specific data }, "meta": { "apiVersion": "v1", "webhookId": "wh_xyz789" }}Event Categories
Section titled “Event Categories”| Category | Events |
|---|---|
| Box | box.created, box.updated, box.deleted |
| Violation | violation.detected, violation.resolved, violation.appealed |
| Grace Period | grace_period.started, grace_period.reminder, grace_period.ending, grace_period.expired, grace_period.resolved |
| License | license.requested, license.approved, license.denied, license.expiring, license.expired, license.revoked |
| Detection | detection.match_found, detection.scan_complete |
See Event Types for detailed event documentation.
Retry Policy
Section titled “Retry Policy”Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
| 7 | 24 hours |
After 7 attempts, the webhook is marked as failed. You can manually retry from the dashboard.
Best Practices
Section titled “Best Practices”1. Respond Quickly
Section titled “1. Respond Quickly”Return a 2xx status code within 30 seconds. Process events asynchronously:
app.post('/webhooks/lmif', async (req, res) => { // Verify signature first if (!verifySignature(req)) { return res.status(401).send('Invalid signature'); }
// Acknowledge immediately res.status(200).send('OK');
// Process asynchronously const event = JSON.parse(req.body); await processEventAsync(event);});2. Handle Duplicates
Section titled “2. Handle Duplicates”Webhooks may be delivered more than once. Use the event ID for idempotency:
async function handleEvent(event) { // Check if already processed const processed = await db.events.findOne({ eventId: event.id }); if (processed) { console.log('Event already processed:', event.id); return; }
// Process and record await processEvent(event); await db.events.insert({ eventId: event.id, processedAt: new Date() });}3. Monitor Failures
Section titled “3. Monitor Failures”Set up alerting for webhook failures:
app.post('/webhooks/lmif', (req, res) => { try { // Process webhook } catch (error) { // Alert on failure alertOps('Webhook processing failed', error); // Still return 200 to prevent retries if it's a processing error res.status(200).send('OK'); }});Testing Webhooks
Section titled “Testing Webhooks”Trigger Test Events
Section titled “Trigger Test Events”await lmif.webhooks.test({ eventType: 'box.created', endpoint: 'https://yoursite.com/webhooks/lmif'});- Go to Settings → Webhooks
- Click your endpoint
- Click Send Test Event
- Select event type
Local Development
Section titled “Local Development”Use a tunneling service for local testing:
# Using ngrokngrok http 3000
# Your webhook URL becomes:# https://abc123.ngrok.io/webhooks/lmifManaging Webhooks
Section titled “Managing Webhooks”List Webhooks
Section titled “List Webhooks”const webhooks = await lmif.webhooks.list();Update Webhook
Section titled “Update Webhook”await lmif.webhooks.update('wh_xyz789', { events: ['box.created', 'box.updated'] // Change subscribed events});Delete Webhook
Section titled “Delete Webhook”await lmif.webhooks.delete('wh_xyz789');Rotate Secret
Section titled “Rotate Secret”const newSecret = await lmif.webhooks.rotateSecret('wh_xyz789');// Update your code with the new secret