Webhooks overview
Webhooks push events to your server in real time, so you do not have to poll.
When something happens in a restaurant — a reservation is created, a guest is
updated, feedback comes in — we send an HTTP POST to a URL you control with a
JSON event describing what happened.
Registering an endpoint
Section titled “Registering an endpoint”Webhook endpoints are self-serve from the back office. An owner or co-owner can manage them under Settings → Developers:
- Add an endpoint with its URL — an HTTPS, publicly reachable address (internal or private hosts are rejected).
- Choose which events it should receive — individual event types or all events.
- Reveal its signing secret (
whsec_…) and store it; you use it to verify signatures. You can rotate it later if it is ever exposed.
From the same screen you can enable, disable, or delete an endpoint, inspect a delivery log showing each attempt’s status and response, resend a past delivery, and send a test event. A restaurant can register up to 5 endpoints.
Each endpoint is pinned to an API version at creation, so the payload shape you receive stays stable.
The event envelope
Section titled “The event envelope”Every delivery is a JSON object with this envelope:
{ "id": "evt_1K8xQ2m4Vd0pErJ7sN1aZ9bQ", "object": "event", "type": "reservation.updated", "created": "2026-06-27T17:30:00Z", "livemode": true, "api_version": "2026-06-27", "data": { "object": { "object": "reservation", "id": "resv_…" }, "previous_attributes": { "party_size": 2 } }}| Field | Description |
|---|---|
id | Unique event id (evt_…). Use this to deduplicate (see below). |
object | Always "event". |
type | The event type, e.g. reservation.updated. See the event catalog. |
created | When the event was emitted — ISO-8601 in UTC (a Z suffix). See the timezone note below. |
livemode | Always true for real events. |
api_version | The version the payload is rendered in (the endpoint’s pinned version). |
data.object | A full snapshot of the affected resource, in the same shape as the API. |
data.previous_attributes | Only on reservation.updated — a map of the changed fields to their previous values. Omitted on every other event type. |
Responding to events
Section titled “Responding to events”Return a 2xx status code quickly (ideally within a few seconds) to acknowledge
receipt. Do the real work asynchronously. Any non-2xx response, a timeout, or a
connection error is treated as a failed delivery and will be retried.
Delivery semantics
Section titled “Delivery semantics”At-least-once, deduplicate on event.id
Section titled “At-least-once, deduplicate on event.id”Delivery is at-least-once. The same event may be delivered more than once
(for example, if your server is slow to acknowledge and we retry, or after a
transient network error). Deduplicate on the event id (evt_…): record
the ids you have processed and ignore repeats. Make your handler idempotent.
No ordering guarantee
Section titled “No ordering guarantee”Events are not guaranteed to arrive in the order they occurred. For example,
you might receive reservation.seated before reservation.confirmed. Do not
assume order. When a decision depends on current state, treat the event as a
hint and fetch the latest resource from the API, or reconcile using each
resource’s updated_at.
Retries and auto-disable
Section titled “Retries and auto-disable”If a delivery fails, we retry with exponential backoff over roughly 3 days.
If every attempt fails for that whole window (the endpoint stays unreachable or
keeps returning errors), the endpoint is automatically disabled and an alert
is raised. You will need to fix the endpoint and have it re-enabled. To recover
events missed while an endpoint was down, re-fetch with
updated_since.