What do webhook events send?

Every event a webhook address can receive (bookings, waitlist, tickets, customers, loyalty), an example message, what is and isn't included, how to check the signature, and what happens when your tool is down.

Your webhook addresses (Settings → Data and policies → Integrations → Configure on Zapier) each receive only the events you tick. This guide lists every event and shows what a message looks like, so you can map the fields in Zapier or Make before a real booking arrives — or press Send test on an address to receive a made-up example of any event. Webhooks are part of the Complete plan.

The events

Bookings

Waitlist

Tickets (one message per order, not per ticket)

Customers

Loyalty

Booking seated and Booking cleared only fire if your team marks bookings that way — see How do I see what ResoFlow is connected to?.

An example message

Every message is a JSON POST with the same outer shape:

{ "id": "evt_3f9a1c0b2d4e5f6a7b8c9d0e", "type": "reservation.modified", "apiVersion": "2026-11-01", "created": "2026-11-14T18:02:11.000Z", "venue": { "id": "the-exchequer", "name": "The Exchequer" }, "data": { "booking": { "id": "res_8Kq2", "date": "2026-11-21", "time": "19:30", "partySize": 4, "durationMinutes": 120, "status": "confirmed", "tables": ["Table 12"], "source": "online", "preference": "Window", "updatedAt": "2026-11-14T18:02:10.000Z" }, "changes": [ { "field": "time", "from": "19:00", "to": "19:30" } ], "customer": { "id": "0123456789abcdef0123456789abcdef" }, "guest": { "name": "Sam Lee", "email": "[email protected]", "phone": "+447700900123" } } }

What is and isn't included

The tool you send to receives this data because you set it up — it's your choice which tools get it, and you're responsible for how they use it.

Checking the signature

Each address has its own signing secret (shown once when you add it). Every message carries:

To check it: join the t value, a full stop and the raw request body; work out an HMAC-SHA256 of that with your secret; compare it with each v1 using a constant-time compare; and reject anything whose t is more than five minutes old. In Node:

const crypto = require("node:crypto"); function verifyResoFlow(rawBody, header, secret) { const pairs = header.split(",").map((p) => p.split("=")); const t = Number((pairs.find(([k]) => k === "t") [])[1]); if (!t Math.abs(Date.now() / 1000 - t) > 300) return false; // replay guard const expected = Buffer.from(crypto.createHmac("sha256", secret).update(${t}.${rawBody}).digest("hex"), "hex"); return pairs.filter(([k]) => k === "v1").some(([, v]) => { const got = Buffer.from(v, "hex"); return got.length === expected.length && crypto.timingSafeEqual(got, expected); }); }

Use the raw body exactly as received — re-serialising the JSON changes the bytes and the check fails. Zapier's Catch Hook can't check a signature without a Code step; Make's Custom webhook can with a filter or a script.

When your tool is down

Related: How do I see what ResoFlow is connected to? · Running ResoFlow as a booking diary