Core concepts
Events and webhooks
Everything that happened, in order, delivered to you and there to read back afterwards.
Two ways to the same event
An event reaches you as a webhook, or you read it back from the module's event list. Same envelope, same identifier, same sequence, so the code that handles a delivery handles a replay without knowing which it got.
If you miss a delivery, the list is where you go. You don't have to ask for it to be sent again.
The envelope
{
"id": "evt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"type": "run.approved",
"schema_version": 1,
"org_id": "org_01J8...",
"stream": "run_enterprise_01J8...",
"sequence": 2,
"occurred_at": "2026-09-08T10:42:57.096Z",
"livemode": false,
"mocked": true,
"source": "run",
"data": { ... }
}
source is the module that owns the fact. Never treat your own copy as the authority: when it matters, read back from the owner.
Sequence, and how you know you missed one
The sequence counts per organisation and per stream, from one, with no gaps. A stream is usually one record: one payroll run, one engagement.
If you hold sequence 41 of a run, you know 42 is next and that nothing came between.
A gap tells you to read the event list from the sequence you have.
Verifying a delivery
Every delivery you get carries a signature over the exact bytes of the body, with a timestamp inside the signature header.
Verify before you parse. Compute the signature over the raw body as you received it, not over a reserialisation of it: re-encoding JSON changes the bytes, and the signature is over bytes. Reject anything whose timestamp is outside the tolerance. That's what stops somebody replaying an old delivery at you.
Two secrets can be active at once, so you never lose a delivery during a rotation: accept a body that verifies under either.
Retries
If you don't answer 2xx, we retry on a published schedule, so you never have to measure it: ten seconds, then a minute, then five, then thirty, then two hours, then five, ten and twenty. After that we stop, and the delivery stays available for you to replay by hand.
Answer 2xx as soon as you've stored the event, and do your work afterwards. If you finish processing before you answer, you'll be retried for being slow.