BookMeTable Integration API · V1 · revision 8
Integration API documentation
Connect a web ePOS or till to BookMeTable. Each restaurant has a permanent numeric id (1, 2, 3…) shown on its Integration tab. Create that venue's API key so the till can list bookings, load guest details, push its floor plan, redeem voucher and offer QR codes, and receive signed webhooks. Guests only see area and table pickers after the till has sent those areas and tables.
Canonical URL: https://bookmetable.uk/API/Doc
Per-restaurant API keys
Create one API key per restaurant. That key can only read and update bookings for that venue. ePOS should store the key against the matching till / shop so incoming reservations are attributed to the correct restaurant.
- Admin: Restaurants → [restaurant] → Integration
- Restaurant portal: Integration
- Platform-wide keys and partners: Admin → Integrations
Every booking includes origin and restaurant so the till can display the source venue even if one ePOS account connects several restaurants:
origin.platform = "bookmetable" origin.restaurant_id = 1 origin.restaurant_name = "Annapurna Nepalese" origin.restaurant_slug = "annapurna-nepalese" origin.booking_url = "https://bookmetable.uk/annapurna-nepalese" source = "bookmetable"
Restaurant id
Every venue is assigned a permanent integer when it is created. The first restaurant is 1, the next is 2, and so on. If a restaurant is deleted, that number is never given to another venue.
The same number appears on the Integration tab and in every API payload:
GET https://bookmetable.uk/api/v1/restaurant
{
"object": "restaurant",
"data": {
"id": 1,
"name": "Annapurna Nepalese",
"slug": "annapurna-nepalese",
"booking_url": "https://bookmetable.uk/annapurna-nepalese",
"table_selection_enabled": false,
"table_lock_minutes": 15
}
}table_selection_enabled stays false until the till has pushed a floor plan with PUT /areas or PUT /tables. After that sync, guests can pick those areas and tables on the booking form.
restaurant.id— permanent numberrestaurant_idandorigin.restaurant_idon bookings — the same number
ePOS should store this number against the till / shop. Do not use the old rst_… UUID as the public restaurant id.
Authentication
Send the restaurant's secret key on every request. Keys start with bmt_live_ and are created on that restaurant's Integration tab. Store them on the ePOS server — not in a public website bundle.
Authorization: Bearer bmt_live_… Accept: application/json Content-Type: application/json
Machine-readable catalog: https://bookmetable.uk/api. Version manifest: https://bookmetable.uk/api/v1.
REST endpoints
Base URL: https://bookmetable.uk/api/v1
Load the connected restaurant
GET https://bookmetable.uk/api/v1/restaurant
data.id is the permanent restaurant number shown on the Integration tab.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /restaurant | Yes | Venue profile. id is the permanent restaurant number (1, 2, 3…). Also hours, capacity, and table_selection_enabled. |
| GET | /bookings | Yes | List reservations. Query: date, from, to, status, floor_status, phone, q (name/email/phone/reference). |
| GET | /bookings/{reference} | Yes | Single booking by reference (e.g. BK-SYF8GG) or booking id. |
| PATCH | /bookings/{reference} | Yes | Update floor_status or cancel (status: cancelled). |
| GET | /areas | Yes | Dining areas and table numbers for this restaurant. |
| PUT | /areas | Yes | Push the till floor plan. BookMeTable creates the same areas and tables. Guest pickers appear only after this sync. |
| GET | /tables | Yes | Flat table list for this restaurant, grouped under the same floor plan as GET /areas. |
| PUT | /tables | Yes | Same as PUT /areas. Send the ePOS tables (nested areas, flat tables, or table_count) and BookMeTable will create them. |
| GET | /tables/availability | Yes | Which tables are free for a date and time. Query: date, time, party_size. |
| POST | /tables/status | Yes | Report a walk-in or blocked table so BookMeTable will not offer it. |
| POST | /offers/redeem | Yes | Scan a loyalty voucher or offer QR and redeem it only for the restaurant this API key is connected to. |
| GET | / | No | Version manifest, schema fields, and changelog for this API version. |
List today's bookings
GET https://bookmetable.uk/api/v1/bookings?date=2026-10-18&status=confirmed
Find a guest by phone or name
GET https://bookmetable.uk/api/v1/bookings?phone=07123456789 GET https://bookmetable.uk/api/v1/bookings?q=Alex
Load one booking
GET https://bookmetable.uk/api/v1/bookings/BK-SYF8GG
Mark seated from the till
PATCH https://bookmetable.uk/api/v1/bookings/BK-SYF8GG
Content-Type: application/json
{ "floor_status": "seated" }Cancel with { "status": "cancelled" }.
Pull the floor plan
GET https://bookmetable.uk/api/v1/areas GET https://bookmetable.uk/api/v1/tables
Check if Outside Table 6 is free at 19:30
GET https://bookmetable.uk/api/v1/tables/availability?date=2026-10-18&time=19:30&party_size=2
Tell BookMeTable a walk-in sat at a table
POST https://bookmetable.uk/api/v1/tables/status
Content-Type: application/json
{ "epos_table_id": "T6", "date": "2026-10-18", "time": "19:30", "status": "occupied" }Scan a voucher or offer QR and redeem it
Send the scanner text for a loyalty voucher or promotional offer. The code is redeemed only for the restaurant on this API key. A QR for another shop is rejected. Loyalty vouchers can be used once. Promotional offers stay valid until their end date.
POST https://bookmetable.uk/api/v1/offers/redeem
Content-Type: application/json
{ "code": "BMT:your-restaurant-slug:LOYAB12CD34" }Apply the returned discount on the till. Field details and error codes are in QR vouchers and offers.
QR vouchers and offers
When the till scans a customer's BookMeTable QR, POST the raw scanner text to /offers/redeem with this restaurant's API key. The code is redeemed only if it belongs to that same shop.
Accepted scanner text:
BMT:restaurant-slug:CODE— voucher or offer QRBMT:CODEor the code on its own- A URL that contains
corcode
If the QR includes a restaurant slug, that slug must match the shop on the API key. The voucher or offer must also be issued by that shop. A code for another restaurant is rejected and is not marked redeemed.
Redeem
POST https://bookmetable.uk/api/v1/offers/redeem
Authorization: Bearer bmt_live_…
Content-Type: application/json
{ "code": "BMT:annapurna-nepalese:LOYAB12CD34" }qr is accepted as an alias for code.
Success
{
"object": "offer_redemption",
"data": {
"code": "LOYAB12CD34",
"kind": "loyalty",
"title": "10% off your next visit",
"discount_type": "percent",
"discount_value": 10,
"discount_label": "10% off",
"currency": "GBP",
"single_use": true,
"restaurant_id": 1,
"restaurant_slug": "annapurna-nepalese",
"redeemed": true
}
}kindisloyaltyorpromotion.discount_typeispercent,fixed_amount, orfree_item.discount_valueis the percent, or the amount in pence when the type isfixed_amount(£5.00 is500).- Loyalty vouchers are single-use. A successful call marks them redeemed. Promotional offers stay valid for every guest until their end date, so
single_useisfalse.
Redeem errors
400 invalid_code— the scan did not contain a code403 wrong_restaurant— the QR or code belongs to another shop404 not_found— no voucher or offer for this shop409 already_redeemed— loyalty voucher already used410 expired— loyalty voucher expired422 offer_not_valid— promotional offer is outside its dates or inactive
Booking object
Every list item, detail response, and webhook uses the same JSON shape so a web ePOS can show guest name, contact details, covers, time, notes, visit state, and which BookMeTable restaurant the booking came from. restaurant_id is that venue's permanent number (not a UUID).
{
"object": "booking",
"data": {
"id": "bkg_8f2c1a",
"reference": "BK-SYF8GG",
"restaurant_id": 1,
"restaurant": {
"id": 1,
"name": "Annapurna Nepalese",
"slug": "annapurna-nepalese",
"booking_url": "https://bookmetable.uk/annapurna-nepalese"
},
"origin": {
"platform": "bookmetable",
"restaurant_id": 1,
"restaurant_name": "Annapurna Nepalese",
"restaurant_slug": "annapurna-nepalese",
"booking_url": "https://bookmetable.uk/annapurna-nepalese"
},
"guest": {
"name": "Alex Guest",
"email": "alex@example.com",
"phone": "07123456789"
},
"party_size": 4,
"covers": 4,
"date": "2026-09-20",
"time": "19:30",
"starts_at": "2026-09-20T19:30:00",
"timezone": "Europe/London",
"status": "confirmed",
"floor_status": "pending",
"visit_completed": false,
"special_requests": "Window table, nut allergy",
"area": { "id": "area_outside", "name": "Outside" },
"table": { "id": "tbl_6", "number": "6" },
"lock_at": "2026-09-20T19:15:00",
"lock_minutes": 15,
"source": "bookmetable",
"created_at": "2026-09-19T12:00:00.000Z",
"updated_at": "2026-09-19T12:00:00.000Z"
}
}Fields: id, reference, restaurant_id, restaurant.id, restaurant.name, restaurant.slug, restaurant.booking_url, origin.platform, origin.restaurant_id, origin.restaurant_name, origin.restaurant_slug, origin.booking_url, guest.name, guest.email, guest.phone, party_size, covers, date, time, starts_at, timezone, status, floor_status, visit_completed, special_requests, area.id, area.name, table.id, table.number, lock_at, lock_minutes, source, created_at, updated_at.
Restaurant profile fields from GET /restaurant: id, name, slug, booking_url, source, timezone, opening_time, closing_time, max_party_size, slot_minutes, active, address, city, postcode, phone, table_selection_enabled, table_lock_minutes.
Areas, tables, and two-way ePOS sync
Guests only see area and table pickers after the till has sent its floor plan. Push that layout with PUT /areas or PUT /tables. BookMeTable then creates the same areas and the same number of tables, and turns guest selection on.
- Floor plan from ePOS. Send areas and tables (or a flat table list /
table_count). Includeepos_area_id/epos_table_idwhen the till has them so later updates match. - Guest books a table. The booking webhook includes
area,table,starts_at, andlock_at(seating time minuslock_minutes, default 15). - ePOS locks the table. At
lock_at, the till should reserve that table so walk-ins cannot sit there. You can also pollGET /bookings?date=…and lock any booking whoselock_athas passed. - Walk-ins and blocked tables. When the till seats a walk-in or marks a table out of service, POST
/tables/statuswithoccupiedorblocked. BookMeTable will not offer that table. Sendfreewhen it is cleared. - Availability check. Before confirming a booking or a walk-in, call
GET /tables/availability. A table is unavailable if BookMeTable already has a reservation or ePOS has posted a hold.
Push the till floor plan (areas + tables)
PUT https://bookmetable.uk/api/v1/areas
Content-Type: application/json
{
"areas": [
{
"name": "Outside",
"epos_area_id": "out",
"tables": [
{ "number": "6", "epos_table_id": "T6", "seats": 4 }
]
},
{
"name": "Downstairs",
"epos_area_id": "down",
"table_count": 8
}
]
}Or send the ePOS table list as-is
PUT https://bookmetable.uk/api/v1/tables
Content-Type: application/json
{
"tables": [
{ "area": "Main hall", "number": "1", "epos_table_id": "T1", "seats": 2 },
{ "area": "Main hall", "number": "2", "epos_table_id": "T2", "seats": 4 },
{ "area": "Garden", "number": "10", "epos_table_id": "G10", "seats": 6 }
]
}Or create one dining room with N tables
PUT https://bookmetable.uk/api/v1/tables
Content-Type: application/json
{ "table_count": 12 }BookMeTable creates matching areas and tables, stores epos_area_id / epos_table_id, and turns guest table selection on. A flat list or table_count replaces the previous till floor plan unless you send "replace": false.
Read the tables BookMeTable created
GET https://bookmetable.uk/api/v1/tables
The response includes areas and a flat tables array with area_name, number, seats, and the ePOS ids. Use those epos_table_id values later with POST /tables/status.
Floor status
Use floor status for the on-site workflow. Booking status (confirmed / cancelled) is separate.
pending → arrived → seated → completed (or no_show).
Allowed values: pending, arrived, seated, no_show, completed.
Webhooks
Register a webhook URL on the restaurant connection. BookMeTable POSTs a signed JSON body when subscribed events occur: booking.created, booking.updated, booking.cancelled, booking.completed.
Verify HMAC-SHA256 of {timestamp}.{raw_body} using your webhook secret.
X-BookMeTable-SignatureX-BookMeTable-TimestampX-BookMeTable-EventX-BookMeTable-Delivery
The webhook data object matches the REST booking object above.
Errors
401— missing or invalid API key404— booking, voucher, or offer not found for this restaurant403— voucher or offer belongs to another restaurant409— loyalty voucher already redeemed410— loyalty voucher expired422— promotional offer is not currently valid400— invalid JSON, floor status, or missing areas / tables / table_count on a floor-plan push503— Integration API disabled platform-wide
Successful JSON responses include X-BookMeTable-Api-Version: v1. Browser tills may call the API cross-origin (CORS + OPTIONS).
Changelog
- v1 r8 (2026-09-23)
- POST /offers/redeem lets the connected ePOS scan a BookMeTable QR and redeem that shop’s loyalty voucher or promotional offer.
- Redemption uses the restaurant on the API key. A code for another shop is rejected.
- Loyalty vouchers are single-use. Promotional offers stay valid for every guest until their dates end.
- v1 r7 (2026-09-21)
- Guest area/table selection is shown only after ePOS has pushed a floor plan (epos_area_id / epos_table_id).
- PUT /areas and PUT /tables accept nested areas, a flat tables list, or table_count and create the same areas and tables in BookMeTable.
- GET /tables returns the flat till table list. table_selection_enabled is true only when that ePOS floor plan exists.
- v1 r6 (2026-09-21)
- Documented permanent numeric restaurant id on GET /restaurant and all booking payloads.
- Public docs and FAQ updated: restaurant.id / restaurant_id / origin.restaurant_id are integers and are never reused.
- v1 r5 (2026-09-21)
- Restaurant id is now a permanent number (1, 2, 3…) assigned in creation order and never reused after delete.
- API restaurant.id, restaurant_id, and origin.restaurant_id use that number instead of rst_… UUIDs.
- v1 r4 (2026-09-20)
- Areas and tables: GET/PUT /areas, GET /tables/availability, POST /tables/status.
- Booking payload includes area, table, lock_at, and lock_minutes so ePOS can lock the table 15 minutes before seating.
- Restaurant profile reports table_selection_enabled and table_lock_minutes.
- v1 r3 (2026-09-20)
- Per-restaurant Integration tab: each venue has its own API key for ePOS.
- Booking payload origin + restaurant.booking_url so the till knows which restaurant the booking came from.
- v1 r2 (2026-09-20)
- Web EPOS booking payload: id, restaurant name/slug, covers, starts_at, visit_completed.
- Look up a booking by reference or internal id; search list by phone or q.
- Filter list by floor_status. CORS + OPTIONS for browser-based tills.
- Restaurant portal amend/cancel now emit booking.updated / booking.cancelled webhooks.
- v1 r1 (2026-06-30)
- Initial Integration API release.
- REST: restaurant, bookings list/detail, PATCH floor_status.
- Webhooks: booking.created, booking.updated, booking.cancelled, booking.completed.
- Auto contract sync on database migration.
Looking for diner help instead? See the FAQ. This page is also available at /API/Doc.