Webhooks
Build a receiver that verifies signatures, acknowledges fast, and survives retries — everything delivery expects from your endpoint, with working code.
How delivery works
When a subscribed event occurs, a delivery is queued and dispatched to your endpoint as an HTTP POST with a JSON body and three headers:
POST /your/webhook/path HTTP/1.1
Content-Type: application/json
X-Webhook-Signature: 7f8a1c… (hex HMAC-SHA256 of the raw body)
X-Webhook-Event: meeting.ended
X-Webhook-Delivery-ID: 9b2e4f10-…The payload envelope is consistent across all events:
{
"id": "evt-uuid",
"type": "meeting.ended",
"timestamp": "2026-06-12T10:30:00Z",
"delivery_id": "9b2e4f10-…",
"organization_id": "org-uuid",
"data": { }
}The data object varies by event — see the event catalog.
Endpoint requirements
- HTTPS with a valid certificate. Plain HTTP endpoints are not a supported target.
- Respond fast. Deliveries time out after 10 seconds. Acknowledge with a
2xximmediately and process asynchronously; any non-2xxstatus or timeout counts as a failure. - Verify the signature before processing. Compute HMAC-SHA256 over the raw request body with your endpoint's shared secret and compare against
X-Webhook-Signaturein constant time. Full verification snippet: authentication.
Retries and backoff
Failed deliveries are retried automatically:
| Attempt | Delay after failure |
|---|---|
| 1 → 2 | 5 minutes |
| 2 → 3 | 30 minutes |
| 3 (final) | marked failed after roughly 2 hours |
A delivery is attempted at most 3 times. Separately, an endpoint that accumulates 10 consecutive failures across deliveries is automatically disabled to protect both sides; re-enable it after fixing the receiver.
A disabled endpoint receives nothing until it is reactivated. Monitor your receiver's error rate — ten straight failures (for example an expired certificate) silently stops your event stream.
Delivery semantics: at-least-once, unordered
Design your consumer around two guarantees that are deliberately weak:
- At-least-once. A delivery can arrive more than once — for example when your endpoint processed the event but the
2xxresponse was lost. Deduplicate ondelivery_id(or the payloadid). - Unordered. Retried deliveries interleave with newer events, so
meeting.endedcan arrive before a delayedmeeting.started. Use the payloadtimestampand your own state rather than arrival order.
Idempotency is the cheapest reliability you will buy here: one delivery_id lookup before processing turns every duplicate and retry into a non-event.
// Idempotent consumption sketch
async function handleDelivery(req) {
if (!verifyWebhook(req.rawBody, req.headers['x-webhook-signature'], SECRET)) {
return respond(401);
}
const event = JSON.parse(req.rawBody);
if (await alreadyProcessed(event.delivery_id)) {
return respond(200); // duplicate — acknowledge, do nothing
}
await markProcessed(event.delivery_id);
await enqueueForProcessing(event); // process async, respond fast
return respond(200);
}Set up a subscription
Webhook endpoints are registered per organization with a target URL, a shared secret, and the list of event types to receive. Endpoints, secrets, and delivery history are managed in the partner administration area at os.thequantumclub.com.
Your endpoint verifies signatures, responds with a 2xx inside 10 seconds, deduplicates on delivery_id, and tolerates out-of-order arrival.

