Webhook Events¶
Receive real-time notifications when events occur in Contio MeetingOS.
Full Reference
For complete event schemas and field documentation, see the Webhook Events Reference.
Webhook Management
To manage webhook delivery status and event filtering, see Webhook Management.
Overview¶
Webhooks allow your application to receive push notifications for key events:
| Event Type | Description |
|---|---|
workflow.assignment.created | Action item assigned to your workflow |
action_item.created | New action item created |
action_item.updated | Action item status changed |
action_item.completed | Action item marked as completed |
meeting.created | New meeting created |
meeting.updated | Meeting properties changed |
meeting.completed | Meeting processing completed, notes available |
calendar_event.created | Calendar event synced from external calendar |
calendar_event.updated | Calendar event updated in external calendar |
calendar_event.deleted | Calendar event deleted from external calendar |
agenda_item.created | Agenda item created in a meeting |
agenda_item.updated | Agenda item updated |
agenda_item.deleted | Agenda item deleted |
participant.added | Participant(s) added to a meeting |
participant.removed | Participant removed from a meeting |
user.connection.revoked | User disconnected from your app |
Quick Start¶
1. Configure Webhook URL¶
Set your webhook URL when creating a workflow:
const workflow = await admin.createWorkflow({
name: 'CRM Integration',
webhook_url: 'https://your-app.com/webhooks/contio',
matching_rules: { keywords: ['follow-up', 'sales'] },
is_active: true
});
2. Implement Webhook Handler¶
import express from 'express';
import { WebhookVerifier } from '@contio/partner-sdk';
const app = express();
const verifier = new WebhookVerifier(process.env.WEBHOOK_SECRET!);
app.post('/webhooks/contio',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-contio-signature'] as string;
const timestamp = req.headers['x-contio-timestamp'] as string;
if (!verifier.verifySignature(req.body, signature, timestamp).isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
processWebhookAsync(event); // Process async, respond fast
res.status(200).json({ received: true });
});
Event Payload Structure¶
All events follow a consistent envelope:
{
"event_type": "workflow.assignment.created",
"event_id": "evt-uuid",
"timestamp": "2025-01-15T10:30:00Z",
"partner_app_id": "app-uuid",
"data": { /* event-specific payload */ }
}
Minimal Payloads
Webhook payloads are intentionally minimal (IDs + key state). Use the Partner API to fetch full details when needed.
Signature Verification¶
All webhooks include a signature for security:
| Header | Description |
|---|---|
X-Contio-Signature | HMAC-SHA256 signature |
X-Contio-Timestamp | Unix timestamp of signature |
Manual Verification¶
import crypto from 'crypto';
function verifyWebhook(
payload: Buffer,
signature: string,
timestamp: string,
secret: string
): boolean {
const signedPayload = `${timestamp}.${payload.toString()}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
Delivery & Retries¶
- Timeout: 30 seconds
- Retries: 3 attempts with exponential backoff
- Retry intervals: 1 min, 5 min, 30 min
Retry Failed Deliveries¶
// List failed deliveries
const deliveries = await admin.getWebhookDeliveries({
status: 'failed'
});
// Retry a specific delivery
await admin.retryWebhookDelivery(deliveryId);
Best Practices¶
- Respond quickly - Return 200 within 5 seconds, process async
- Verify signatures - Always validate webhook authenticity
- Handle duplicates - Use
event_idfor idempotency - Monitor failures - Check delivery status regularly