Webhooks
Receive signed events when records change, and verify each delivery.
Webhooks send an HTTPS request to your endpoint when something changes in the workspace. They are included on Pro and Enterprise.
#Add an endpoint
- Open Settings → Webhooks and choose Add an endpoint.
- Enter your HTTPS address and choose the events to send.
- Copy the signing secret. You need it to verify deliveries.
#Events
| Event | Sent when |
|---|---|
record.created | A record was created. |
record.updated | A record was changed. |
record.deleted | A record was permanently deleted. |
opportunity.stage_changed | An opportunity moved stage. |
opportunity.won | An opportunity moved to a won stage. |
opportunity.lost | An opportunity moved to a lost stage. |
task.completed | A task was marked done. |
email.received | An email arrived in a connected mailbox. |
meeting.analyzed | A recorded meeting finished analysis. |
forecast.snapshot_created | A forecast snapshot was taken. |
Each delivery carries the event name in x-syncon-event and a delivery id in x-syncon-delivery. A failed delivery is retried with growing gaps, up to eight attempts.
#Verify a delivery
The x-syncon-signature header looks like t=1729590000,v1=…: a Unix timestamp and an HMAC-SHA256, in hex, of the timestamp, a full stop and the raw request body. Reject a delivery whose timestamp is more than five minutes old or whose signature does not match.
import { createHmac, timingSafeEqual } from "node:crypto";
// body: the raw request body as a string, before any JSON parsing
export function isGenuine(body, header, secret) {
const parts = Object.fromEntries(
(header ?? "").split(",").map((part) => {
const at = part.indexOf("=");
return [part.slice(0, at).trim(), part.slice(at + 1).trim()];
}),
);
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp) || !/^[0-9a-f]{64}$/.test(parts.v1 ?? "")) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret).update(`${timestamp}.${body}`).digest();
return timingSafeEqual(expected, Buffer.from(parts.v1, "hex"));
}