Webhooks
Subscribing to events, verifying signatures, and surviving retries.
Rather than polling for changes, subscribe an endpoint to events. Settings → Integrations → Webhooks.
Events
| Event | Fires when |
|---|---|
lead.created | A lead is created by any route |
lead.status_changed | A lead moves stage |
lead.assigned | Ownership changes |
call.logged | A call is recorded |
message.received | An inbound message arrives |
deal.won | A deal reaches a won stage |
deal.lost | A deal reaches a lost stage |
callback.missed | A scheduled callback slot passes untouched |
Payload
{
"event": "lead.created",
"event_id": "01KYM97KCJK416C465Y2A8AN3N",
"occurred_at": "2026-07-29T11:42:03.512Z",
"data": { "object": "lead", "public_id": "01H8XGJWBWBAQ4S1PT7C2N3M4K" }
}The payload carries identifiers, not a full record. Fetch the object if you need its current state — by the time your handler runs, the copy in a webhook body may already be stale.
Verifying the signature
Every delivery carries X-Nexus-Signature: an HMAC-SHA256 of the raw request body, keyed with the endpoint's signing secret.
const expected = crypto
.createHmac('sha256', process.env.NEXUS_WEBHOOK_SECRET)
.update(rawBody) // the raw bytes — NOT a re-serialised object
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
return res.status(400).end();
}Use a constant-time comparison. A plain === on a signature leaks, one byte at a time, how much of a guess was correct.
Retries and idempotency
A non-2xx response is retried with exponential backoff for up to 24 hours.
Deduplicate on event_id. A retry sent after your handler succeeded but timed out will deliver the same event again, and processing it twice is a problem only your side can prevent — we cannot know whether your work completed.
Return 200 as soon as you have durably recorded the event, then do the work afterwards. A handler that spends thirty seconds processing before responding will be retried while it is still running.
The delivery log
Settings → Integrations → Webhooks → [endpoint] → Deliveries shows every attempt with its response code and body, so a failing endpoint is visible rather than silently dropping events. An endpoint that fails for 24 hours is disabled and the workspace owners are emailed.
Stuck on a response you did not expect? Send us the request_id from the error body and we can trace the exact call — contact support.