The message id — stable across retries of the same message. Deduplicate on the body’s id (the signal id), not on this: an endpoint whose api_version changes while a signal is being retried can receive that signal once per version, as two messages with two message ids.
svix-timestamp*string
When this attempt was sent, in Unix seconds.
svix-signature*string
Signature over the id, timestamp and raw body, made with your endpoint’s secret. Verify it with any Standard Webhooks library before trusting the payload.
Opaque sig_-prefixed id. Identifies WHAT HAPPENED, and never changes.
object*string
Value in"signal"
type*string
Value in"booking.updated"
created*string
When the signal was emitted (ISO-8601, UTC) — not when it was delivered.
Formatdate-time
sequence*integer
Per-club counter. A staleness key, not an ordering guarantee. Use it to compare two signals about the SAME resource: the lower one is older and may be discarded. Gaps are normal and carry no meaning — a webhook endpoint receives only the types it subscribes to, and GET /v1/signals returns only the signals your key’s scopes cover — so never infer loss from a gap, wait for a missing number, or compare sequence across clubs.
api_version*string
The API version this payload is shaped by, e.g. 2026-11-01. A signal is delivered and returned at your version (your webhook endpoint's or your request's), rendered down from the version it was created at. A signal created BEFORE the version you read at is returned as it was created, so this field can be older than your version — never newer. See /developers/versioning.
data*
data.object is the matching /v1 resource — the same fields carrying the same values that endpoint returns. Compare it as parsed JSON: key order is not part of the contract.
previous_attributes?
Only the fields that changed, holding their PRIOR values. Present on *.updated types; absent on create/delete types and on the first signal about a resource. Semantics: the values as of the last signal we sent you about this resource — not immediately before one particular write. If a change ever reached the resource without a signal, the next diff covers both, so you converge rather than drift.
updated_at is never reported here. It moves on every write by definition, so including it would make the diff never empty and defeat the suppression of no-op updates. Read its new value from data.object; its absence from this object does not mean it did not change.