What you can subscribe to
The list of things we'll tell you about, where to get it, and why your code must ignore what it doesn't recognise.
Event names read like a sentence about what happened:
clients.client.created
clients.client.updated
clients.note.added
employees.time_off.requestedThe shape is <module>.<thing>.<what happened>. So you can guess at the pattern without
memorising individual names, and a new kind of thing in a module doesn't change the rules.
Get the list from the API, not from here
Don't hard-code a list off this page. The endpoint dialog in Webhooks lists everything available, grouped by module, generated from what the API actually fires — so it can't disagree with reality, and new events appear there without anyone updating docs.

Where events come from
An event exists because a module declared an automation trigger for it. Two useful consequences:
- If you can build an automation on it, you can webhook on it. The list of triggers available inside a site and the list of webhook events are the same list.
- There's no separate registration step. A module gains a webhook event by gaining a trigger.
Coverage is still filling in
The catalogue reflects declared triggers, and not every module fires every event it declares yet. Check the live list for what's actually flowing — and if something is listed but never arrives, tell us. That's a gap on our side rather than a design limit.
Which events are listed
The catalogue is curated to what you can rely on: events of released modules (beta or public) and the platform's own. Modules still in development declare triggers too, but they stay off the list until they ship, so you can't subscribe to something whose payload may still change shape.
Every entry carries a payload_schema — the fields data.object is guaranteed to hold,
with their types and whether they're always present:
{
"key": "data.record.created",
"label": "Custom data record created",
"payload_schema": {
"collection": { "type": "string", "required": true },
"record": { "type": "object", "required": true }
}
}Fields can be added to a payload without an API version change; they are never removed or retyped without one.
Your code has to ignore what it doesn't know
We add new event types without changing the API version, so your receiver must:
Return 2xx for types you don't handle. Returning an error for an unrecognised event
counts as a failed delivery, and enough failures switch your endpoint off. This is a real
way to break your own integration.
Tolerate new fields inside data.object. See
what gets a new version.
function handle(event) {
switch (event.type) {
case 'clients.client.created':
return onCustomerCreated(event.data.object);
case 'clients.client.updated':
return onCustomerUpdated(event.data.object);
default:
// Subscribed to something new, or a type added since we deployed.
// Not an error. Saying so would count against us.
return;
}
}Subscribing
events is an explicit list — there's no wildcard. Send the full set you want:
{
"events": [
"clients.client.created",
"clients.client.updated",
"clients.client.deleted"
]
}Subscribe narrowly. An endpoint signed up for everything gets a lot of traffic it does nothing with, which makes a real failure much harder to spot in the delivery log.
One endpoint or several?
Both work.
One endpoint with a dispatch table is simpler to run and gives you a single delivery log to read. Good default.
Several endpoints are worth it when different systems own different events, or when you want one to be able to fail without taking the other down — being switched off after repeated failures happens per endpoint.