Developers
API and webhooks
For your own kiosk, wall display, till or any other system you run, not for normal day to day use of Tablez. A small REST API to read and action your own bookings, and signed webhooks that fire the moment something happens.
Not needed to use Tablez itself. Skip this page unless you are building something of your own.
Access
Turning it on
API access is switched on per account, not on by default for every plan. It comes with the Group plan, and we are happy to switch it on for any other account on request, free while you are building and testing. Get in touch and tell us roughly what you want to connect, a kiosk, a POS, a wall display, anything else.
Once it is on, generate a key from Settings → API and webhooks in your dashboard. The raw key is shown once, at creation, then never again, so copy it somewhere safe straight away. Creating a new key retires the old one immediately.
Authentication
Calling the API
Send your key as a bearer token on every request. Always call the main Tablez host below, never your own yourname.tablez.uk booking address, that one is for the public booking page only.
curl https://tablez.uk/api/v1/venue \
-H "Authorization: Bearer tbz_live_123_xxxxxxxxxxxxxxxxxxxxxxxx"
300 requests per 5 minutes per key. Every response is JSON, including errors.
Endpoints
What you can do
GET /api/v1/venue — your account
Returns your venue id, name, slug and plan. Good for a quick "is my key working" check.
GET /api/v1/bookings — list bookings
Query params: date (YYYY-MM-DD), or from/to for a range, status (pending, checking, confirmed, declined, cancelled, arrived, no_show), updated_since (an ISO timestamp, for polling as a backup to webhooks), limit (1 to 200, default 50). Newest updated first.
GET /api/v1/bookings/:ref — one booking
The reference is the TZ-XXXXXX code, the same one on the confirmation email and the dashboard.
POST /api/v1/bookings/:ref/confirm — accept it
Only works on a booking waiting for a decision (pending or checking). Sends the customer their confirmation email and text, exactly as if you had tapped Accept in the dashboard.
POST /api/v1/bookings/:ref/decline — decline it
Body: {"reason": "Fully booked", "note": "optional"}. Sends the customer their decline email, and frees a spot on the waitlist if there is one waiting.
POST /api/v1/bookings/:ref/cancel — cancel it
Marked as cancelled by the venue. The customer gets the usual cancellation email.
GET /api/v1/tables — your floor plan
Table names, seats and shapes, from Settings → Edit floor plan. This is the static layout, not live occupancy, for that use the dashboard's own floor plan.
POST /api/v1/webhooks/test — send a test event
Fires one test webhook at your saved address right now, useful while you are building your receiver. The same button exists in the dashboard.
Example
Accepting a booking
curl -X POST https://tablez.uk/api/v1/bookings/TZ-4F2KQ1/confirm \
-H "Authorization: Bearer tbz_live_123_xxxxxxxxxxxxxxxxxxxxxxxx"
Response:
{
"ref": "TZ-4F2KQ1",
"status": "confirmed",
"source": "online",
"date": "2026-10-04",
"time": "19:00",
"party": 4,
"name": "Jo Bloggs",
"email": "[email protected]",
"phone": "07700 900123",
"requests": null,
"allergy": null,
"createdAt": "2026-09-30T18:04:11.000Z",
"updatedAt": "2026-09-30T18:06:52.000Z"
}
Webhooks
Getting told the moment something happens
Set your webhook address from Settings → API and webhooks, tick which events you want, and we POST a JSON event to it as things happen: booking.created (a new booking needs a decision, or an instant one just landed), booking.confirmed, booking.declined, booking.cancelled. Your address must be https.
Every attempt is signed, so you can check it genuinely came from Tablez and was not replayed or tampered with. The header looks like:
Tablez-Signature: t=1759257600,v1=8f1e2c...
Check it by HMAC-SHA256 hashing the timestamp, a full stop, then the exact raw request body, using your webhook signing secret (shown once your webhook address is saved), and comparing it to v1. In Node:
const crypto = require('crypto');
function verify(rawBody, header, secret) {
const [t, v1] = header.split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const ok = expected.length === v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
// Also check t is recent (say, within 5 minutes) to guard against a replayed request.
return ok && Math.abs(Date.now() / 1000 - Number(t)) < 300;
}
If your endpoint is down or slow, we retry twice more (after 1 and 4 seconds), then give up and show the last result on the API and webhooks settings page. Bookings themselves are never blocked or delayed waiting on your webhook, a customer's booking always completes first.
Example event body:
{
"id": "evt_9c1a2b3d4e5f6789",
"type": "booking.created",
"createdAt": "2026-09-30T18:04:11.000Z",
"venue": { "id": 123, "name": "The Demo Arms", "slug": "demo-arms" },
"data": { "ref": "TZ-4F2KQ1", "status": "pending", "...": "same shape as the booking endpoints above" }
}
Good to know
A few things worth knowing before you build
- This is for your own systems, not for anything a customer uses directly. A key gives full read and accept/decline access to your bookings, treat it like a password.
- Confirm and decline follow the same rules as the dashboard: you cannot confirm a booking that is already confirmed, or decline one that is already cancelled, the API returns a plain error explaining why.
- Webhooks tell you fast, but they can occasionally be missed (a restart, a network blip). Use
GET /api/v1/bookings?updated_since=...every so often as a backstop, not just the webhook. - Revoking your key from the dashboard stops it working immediately, useful if it ever leaks.
Questions, or want API access switched on for your account? Contact us.