Public booking (hospitality)

Hold a table (guest checkout, step 1)

post/api/book/{slug}/reservations

Takes a 10-minute hold on a table and returns its id. The guest then confirms it with PATCH once they have typed their details; that gap is exactly what the hold protects.

The slot is re-derived server-side and matched exactly against the requested startsAt. The exclusion constraint, not the availability read, is what actually makes the allocation safe.

400 versus 409. The two are not interchangeable and this route distinguishes them: 400 means the request can never succeed (that time is outside every service period, no table seats a party that size, or the venue is closed), 409 means it was bookable and someone else has it. When the allocator comes back empty it is re-run against an empty venue to decide which. The appointments checkout draws the same line, and the widget relies on it; it re-loads the availability grid on 409 only.

areaId/levelId (migration 0030) narrow the candidate tables the same way the availability route does. tableId requests a specific one of them; honoured only if tablePickerEnabled is on for this org (silently ignored, not rejected, otherwise, so a stale client that cached the toggle a moment before an admin disabled it still completes a normal auto-pick booking) and only if that table is still in the candidate set for this EXACT slot; losing that race is the same 409 family as every other "someone else got there first" outcome here, not a 400; the time itself is still bookable, just not with that one table.

Path Parameters

slug*string

The organization's public booking slug, i.e. the {slug} in /{slug}. Only orgs with status active resolve; anything else is a 404.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/api/book/string/reservations" \  -H "Content-Type: application/json" \  -d '{    "startsAt": "2019-08-24T14:15:22Z",    "partySize": 1  }'
{  "reservationId": "54c41ef9-5629-4a9c-bb0d-10f615966bd0",  "expiresAt": "2019-08-24T14:15:22Z",  "holdMinutes": 0}