Webhook event reference
What this covers
All nineteen events, when each fires, and what to key on. Requires the Webhooks feature.
Reservations
| Event | Fires when |
|---|---|
reservation.created | Any booking is created — staff, online, chatbot, walk-in or API |
reservation.updated | Date, time, pax, table, duration, requests or notes change |
reservation.confirmed | Status becomes confirmed |
reservation.arrived | The guest is marked arrived |
reservation.seated | The guest is seated |
reservation.completed | The visit is completed |
reservation.cancelled | Cancelled, by staff or guest |
reservation.no_show | Marked a no-show, by hand or by the automatic sweep |
The status events are what make a live kitchen or floor display possible. Note arrived,
seated and completed fire webhooks even though they send the guest nothing (link
What Tabledoo sends, and when).
Walk-ins and event bookings
Walk-ins fire the full set. A walk-in is an ordinary booking with a walk-in source, so it
produces reservation.created and every status event that follows.
Event bookings are a separate kind of record and do not fire reservation events. If your integration must track event bookings, that is worth confirming with support before you design around it (link Taking event bookings).
Guests
| Event | Fires when |
|---|---|
guest.created | A guest profile is created — including automatically, from an online or chatbot booking |
guest.updated | Guest details change |
These two are what a CRM sync should listen to. Remember profiles are created automatically when an unknown
guest books, so guest.created fires more often than staff adding people by hand.
Waitlist
| Event | Fires when |
|---|---|
waitlist.created | A party is added to the waitlist |
waitlist.converted | A waitlist entry becomes a real booking |
waitlist.cancelled | An entry is closed as cancelled or a no-show |
Useful, and worth flagging: the waitlist has no API endpoints, so these events are the only programmatic view of it. A wait-time display or a queue screen has to be built on them (link The waitlist).
Orders
| Event | Fires when |
|---|---|
order.placed | Guests submit an order from a table |
order.status_updated | An order moves — confirmed, preparing, served |
order.item.status_updated | A single item moves |
order.cancelled | An order is cancelled |
Because order and item status stay in step both ways, a single action can produce both an order event and item events. Decide which level your integration keys on and ignore the other, or you will double-count (link The Orders board).
Summons
| Event | Fires when |
|---|---|
summon.created | A guest calls a waiter or requests the bill |
summon.cleared | Staff clear it |
The one genuinely time-critical pair — a guest waiting with a raised hand. If you are driving a floor buzzer or a staff watch, these are the events, and your endpoint's response time matters (link Call waiter and request bill).
The payload
Every delivery uses the same envelope, whatever the event:
{
"event": "reservation.confirmed",
"timestamp": "2026-10-02T18:14:22+00:00",
"api_version": "v1",
"tenant": { "property_code": "oldbell", "name": "The Old Bell" },
"data": { ... }
}
data holds the record in the same shape the API returns it, so a reservation payload looks like
a reservation from GET /reservations/{id}. One integration can handle both sources with the same
parsing code (link API reference).
What to key on
X-Tabledoo-Delivery-Id— for idempotency. Always.event— to route. Or theX-Tabledoo-Eventheader, which saves parsing the body first.- The record's
idinsidedata— your stable link to the booking, guest or order. It does not change. timestamp— to order events, since delivery order is not guaranteed.api_version— so a future version does not surprise you.
Do not key on field positions or assume the field list is fixed: new fields may be added, which is why your parser should ignore what it does not recognise rather than failing.
Monthly delivery allowance
Your plan sets how many webhook deliveries you get per calendar month. Reach it and further events are skipped for the rest of the month — silently, with no delivery record and no warning.
Two things follow:
- Subscribe only to events you act on. The cheapest way to stay inside the allowance.
- Watch out for high-volume events. On a busy QR-ordering night,
order.item.status_updatedcan fire many times per table. If you only need whole-ticket progress, subscribe toorder.status_updatedalone.
Your allowance is part of your plan (link Your plan and what it includes).
Good to know
Every active endpoint subscribed to an event gets its own delivery, each counting separately against the allowance.
Deactivated endpoints receive nothing and consume nothing.
Events are not queued for later if your endpoint is down. They are retried four times over about an hour and then abandoned — recoverable only by a manual retry (link Delivery history and retries).