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.
Deliveries carry guest data
Section titled “Deliveries carry guest data”An endpoint is registered by the restaurant and is not tied to an API key, so
no scope filters what it receives. A reservation delivery carries the booking’s
contact details (contact_email, contact_phone), the guest’s notes
(guest_notes) and the restaurant’s private note (internal_notes), the
guest.* events carry the guest profile, a waitlist entry carries the guest’s
notes, and feedback.received carries the guest’s comment. On the API the
same fields need guests:read: see
Guest data on a booking.
A waitlist entry’s private note is the one thing no payload carries.
Treat the endpoint URL like a credential to the restaurant’s guest book. Whoever answers at that URL receives every guest’s contact details as they change, so register only a host you control, and keep the URL out of tickets, chat and shared configuration.
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 } }}Every field on it, and the two clocks one payload carries, are on The webhook event object.
Responding to events
Section titled “Responding to events”Return a 2xx status code to acknowledge receipt, then do the real work
asynchronously. A delivery times out after 10 seconds, on the connection and
on the read alike, so an endpoint that finishes its own processing before it
answers starts failing the moment that processing is slow. Any non-2xx
response, a timeout, or a connection error is a failed delivery and is retried.
Your response body is read up to 64 KiB and the read is then abandoned, which fails the delivery. The first 500 bytes are kept in the delivery log, so a short diagnostic string is worth returning and a full page of HTML is not.
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”A failed delivery is retried on a fixed schedule: 9 attempts in all, spanning about 2.7 days. The waits between them are 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, 24 hours and 24 hours. After the ninth attempt the delivery is marked failed and is never tried again.
One delivery that succeeds clears the endpoint’s failure count. 15 consecutive
deliveries that exhaust all 9 attempts disable the endpoint, and an alert is
raised. Fix the endpoint, re-enable it from the back office, then recover the
events missed while it was down by re-fetching with
updated_since.
Source addresses are not published
Section titled “Source addresses are not published”Service publishes no list of IP addresses that deliveries come from, and commits to no fixed range. Authenticate a delivery by its signature, not by where it appears to come from.