Reference

Webhooks

Webhooks push reservation and waitlist events to your systems as signed JSON. Configure endpoints in the console under API & webhooks; the signing secret is shown once on creation.

Events

Event types
reservation.createdeventNew booking from any channel
reservation.updatedeventStatus, tables, or details changed
reservation.cancelledeventCancelled by guest, staff, or API
waitlist.createdeventNew waitlist entry
waitlist.updatedeventWaitlist status changed

Delivery format

POST to your endpoint
POST /your/webhook HTTP/1.1
Content-Type: application/json
x-webhook-event: reservation.created
x-webhook-signature: t=1781449200,v1=4f0b1c...

{
  "id": "evt_5d2b8a13c0de4f6e",
  "type": "reservation.created",
  "restaurantId": "rst_1",
  "createdAt": "2026-06-10T17:00:00.000Z",
  "data": {
    "reservationId": "res_9f31",
    "publicReference": "rr_7f3a91",
    "status": "confirmed",
    "startTime": "2026-06-12T17:00:00.000Z",
    "endTime": "2026-06-12T19:00:00.000Z",
    "partySize": 4,
    "tableIds": ["t-03"],
    "guest": { "firstName": "Mara", "lastName": "Schneider" }
  }
}

Verifying signatures

The signature header carries a unix timestamp and an HMAC-SHA256 of `${timestamp}.${rawBody}` with your webhook secret. Reject anything older than five minutes and compare with a constant-time check.

Node.js verification
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((part) => part.split("="))
  );
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!parts.t || !parts.v1 || age > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(parts.v1, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Retries

A delivery counts as successful on any 2xx response within five seconds. Failures with status 408, 429, or 5xx are retried with exponential backoff (1, 5, 15, 60, then 240 minutes) up to the endpoint's retry limit. Every attempt is recorded in the delivery log with status, response code, and body excerpt; the console shows the same log.

Testing

Send a test event from the console (API & webhooks, then Send test event) or through the API with the webhooks:test scope.

Request
curl -X POST "$BASE/webhooks/test" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "eventType": "reservation.created" }'