Skip to content

Tables & pricing

The floorplan model: tables belong to a floor and (optionally) a seating area. You can block tables for a window, combine them for larger parties, let smart tables auto-optimise assignment, and attach price lists that set a default deposit/min-spend per table. Every endpoint is under /api/my-venues/:venueId/… and is operator (client role, venue-scoped) - send an Authorization: Bearer token from the Authentication flow. All prices are integer pence.

Method Path Purpose Auth
GET /api/my-venues/:venueId/tables List tables operator
GET /api/my-venues/:venueId/tables/:id Get a table operator
POST /api/my-venues/:venueId/tables Create a table operator
PUT /api/my-venues/:venueId/tables/:id Update a table operator
DELETE /api/my-venues/:venueId/tables/:id Delete a table operator
POST /api/my-venues/:venueId/tables/set-type Bulk set table type operator
POST /api/my-venues/:venueId/tables/set-area Bulk assign seating area operator
GET /api/my-venues/:venueId/tables/blocks List table blocks operator
POST /api/my-venues/:venueId/tables/block Block tables for a window operator
PATCH /api/my-venues/:venueId/tables/blocks/:id Edit a block operator
DELETE /api/my-venues/:venueId/tables/blocks/:id Delete a block operator
POST /api/my-venues/:venueId/tables/unblock Clear all blocks for tables operator
GET /api/my-venues/:venueId/tables/combos List combinations operator
POST /api/my-venues/:venueId/tables/combos Create a combination operator
PATCH /api/my-venues/:venueId/tables/combos/:id Override/reset a combination’s capacity operator
DELETE /api/my-venues/:venueId/tables/combos/:id Delete a combination operator
GET /api/my-venues/:venueId/floors List floors operator
GET /api/my-venues/:venueId/floors/:id Get a floor + its tables operator
POST /api/my-venues/:venueId/floors Create a floor operator
PUT /api/my-venues/:venueId/floors/:id Update a floor (canvas) operator
PUT /api/my-venues/:venueId/floors/:id/default Set the default floor operator
DELETE /api/my-venues/:venueId/floors/:id Delete a floor operator
GET /api/my-venues/:venueId/seating-areas List seating areas operator
POST /api/my-venues/:venueId/seating-areas Create a seating area operator
PUT /api/my-venues/:venueId/seating-areas/reorder Reorder seating areas operator
PUT /api/my-venues/:venueId/seating-areas/:id Rename a seating area / set its group operator
DELETE /api/my-venues/:venueId/seating-areas/:id Delete a seating area operator
GET /api/my-venues/:venueId/seating-area-groups List seating area groups operator
POST /api/my-venues/:venueId/seating-area-groups Create a group operator
PUT /api/my-venues/:venueId/seating-area-groups/reorder Reorder groups operator
PUT /api/my-venues/:venueId/seating-area-groups/:id Rename a group operator
DELETE /api/my-venues/:venueId/seating-area-groups/:id Delete a group operator
GET /api/my-venues/:venueId/smart-tables Get smart-table settings operator
PUT /api/my-venues/:venueId/smart-tables Update smart-table settings operator
POST /api/my-venues/:venueId/smart-tables/reassign Run smart reassignment now operator
GET /api/my-venues/:venueId/pricelists List price lists operator
POST /api/my-venues/:venueId/pricelists Create a price list operator
PUT /api/my-venues/:venueId/pricelists/:id Update a price list operator
DELETE /api/my-venues/:venueId/pricelists/:id Delete a price list operator
PUT /api/my-venues/:venueId/pricelists/:id/tables Bulk set/clear price for selected tables operator
PUT /api/my-venues/:venueId/pricelists/:id/tables/:tableId Per-table price override operator
POST /api/my-venues/:venueId/tables/:id/dirty Mark a table dirty, or clear the flag operator
POST /api/my-venues/:venueId/integrations/:provider/backfill Pull historic till sales into a date range operator
POST /api/my-venues/:venueId/integrations/:provider/reconcile Re-match till sales to tables over a date range operator

POST /api/my-venues/:venueId/tables takes table_number (required), capacity (default 4) and status (default active). Position, shape and type are synced through the floor canvas (below) or set in bulk with set-type / set-area.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tables" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"table_number":"12","capacity":6,"status":"active"}'
{ "success": true, "id": "tbl_12" }

Update with PUT /api/my-venues/:venueId/tables/:id (table_number, capacity, status) and remove with DELETE /api/my-venues/:venueId/tables/:id. GET /api/my-venues/:venueId/tables accepts ?date=&time=&duration= to decorate each row with is_blocked / is_taken. Add exclude_booking_id to leave one reservation out of the is_taken check (handy when re-seating an existing booking, so its own table doesn’t read as taken).

POST /api/my-venues/:venueId/floors takes name and optional sort_order.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/floors" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Ground Floor","sort_order":0}'
{ "success": true, "id": "flr_1" }
Terminal window
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/floors/flr_1" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Ground Floor","canvas_data":[{"type":"table","tableNumber":"12","tableType":"booth","minCovers":2,"maxCovers":6,"shape":"rect","size":"large","x":120,"y":80}]}'
{ "success": true }

PUT /api/my-venues/:venueId/floors/:id/default marks that floor as the venue’s default room. A venue has at most one default, so this clears the flag on every other floor and sets it on this one in a single step. No body is needed.

POST /api/my-venues/:venueId/seating-areas creates a named area (name, plus an optional group_id); PUT renames it (name) and/or moves it into a group (group_id - send null or "" to un-group), and DELETE detaches its tables then removes it. Assign tables to an area in bulk with POST /api/my-venues/:venueId/tables/set-area (table_ids, seating_area_id - send null to detach), and set their type with POST /api/my-venues/:venueId/tables/set-type (table_ids, table_type one of standard, low, high, booth, bar).

To save a custom order, send the areas in the order you want with PUT /api/my-venues/:venueId/seating-areas/reorder and a body of { "area_ids": ["area_1", "area_2", ...] }. Each area is stored at its position in the list, and that order is what the reservations grid shows. Only areas that belong to this venue are touched.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/seating-areas" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Garden"}'
{ "success": true, "id": "area_1", "name": "Garden" }

A seating area group is a guest-facing name for one or more seating areas (for example Inside = High tables + Low tables). Guests pick the group and are seated in any of its areas; staff views keep the real area. Each area belongs to at most one group.

  • GET /api/my-venues/:venueId/seating-area-groups returns { "data": [{ "id", "name", "sort_order" }] } in display order. Membership lives on the area: read each area’s group_id from GET .../seating-areas.
  • POST .../seating-area-groups with { "name": "Inside" } creates a group and returns { "success": true, "id", "name", "sort_order" } (201). Names are trimmed and capped at 120 characters.
  • PUT .../seating-area-groups/:id with { "name": "..." } renames it.
  • PUT .../seating-area-groups/reorder with { "group_ids": [...] } saves the order guests see.
  • DELETE .../seating-area-groups/:id un-groups its areas and removes its "group:<id>" entry from every table profile and access rule guest_pick_area_ids list at the venue.

To add an area to a group, PUT /api/my-venues/:venueId/seating-areas/:areaId with { "group_id": "GROUP_ID" }. A group_id that isn’t a group of this venue is rejected with 400. To offer a group in “guest picks area” mode, add "group:GROUP_ID" to the profile’s or rule’s guest_pick_area_ids.

POST /api/my-venues/:venueId/tables/block reserves one or more tables for a window. table_ids, from and to are required; reason defaults to “Venue Reserved”. Edit a block with PATCH .../tables/blocks/:id (reason, blocked_from, blocked_to), delete one with DELETE .../tables/blocks/:id, or clear every block on given tables with POST .../tables/unblock (table_ids).

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tables/block" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"table_ids":["tbl_12","tbl_13"],"from":"2026-07-04T18:00:00","to":"2026-07-04T23:00:00","reason":"Private event"}'
{ "success": true, "ids": ["blk_1", "blk_2"], "rule_id": null }

To block the same tables across several dates in one call, send a windows array of { "from": ..., "to": ... } objects instead of a single top-level from/to. Each window becomes its own block, and every block in the batch shares one rule_id so the set can be managed as a series (a single window leaves rule_id as null). Up to 500 occurrences are allowed per call, so set an end date on open-ended patterns.

{
"table_ids": ["tbl_12"],
"windows": [
{ "from": "2026-07-04T18:00:00", "to": "2026-07-04T23:00:00" },
{ "from": "2026-07-11T18:00:00", "to": "2026-07-11T23:00:00" }
],
"reason": "Weekly private hire"
}

When a block belongs to a series, add ?scope=series to DELETE .../tables/blocks/:id to remove every occurrence sharing its rule_id, or send { "scope": "series", "reason": "..." } to PATCH .../tables/blocks/:id to relabel the whole series in one go (start and end stay per-occurrence). Without scope=series, both verbs act on the single occurrence only.

POST /api/my-venues/:venueId/tables/combos joins two or more tables into one bookable unit; combined_capacity is computed from the members. Remove one with DELETE .../tables/combos/:id.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tables/combos" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Booth A+B","table_ids":["tbl_12","tbl_13"]}'
{ "success": true, "id": "cmb_1", "combined_capacity": 8 }

By default a combination’s capacity is the sum of its member tables. To set it by hand, send PATCH /api/my-venues/:venueId/tables/combos/:id with { "combined_capacity": 10 }. Pass null (or leave it blank) to reset the capacity back to the auto sum. The response echoes the value in effect and the auto sum it would fall back to:

{ "success": true, "combined_capacity": 10, "auto_capacity": 8, "override": true }

GET /api/my-venues/:venueId/smart-tables returns the auto-assignment settings; PUT updates them. reassign_enabled runs a daily pass that moves unlocked reservations to optimal tables at reassign_time; duration_enabled extends the hold for larger parties. reassign_last_run is cron-managed and read-only.

Three optional fields tune the smart-duration extension (all accepted on PUT and returned on GET):

  • duration_per_cover_mins - extra minutes added to the hold per cover once the party reaches the large-party threshold (default 10).
  • duration_large_party_threshold - the party size at which the extension kicks in (default 5).
  • duration_max_total_mins - an absolute cap on the total hold in minutes. Send null (or leave it blank) for no cap.
Terminal window
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/smart-tables" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"reassign_enabled":true,"reassign_time":"06:30","duration_enabled":true}'
{
"success": true,
"data": {
"reassign_enabled": true,
"reassign_time": "06:30",
"reassign_last_run": null,
"duration_enabled": true,
"duration_per_cover_mins": 10,
"duration_large_party_threshold": 5,
"duration_max_total_mins": null
}
}

POST /api/my-venues/:venueId/smart-tables/reassign runs the same optimisation as the daily pass on demand, for one venue and one day. It defaults to today; add ?date=YYYY-MM-DD (or send { "date": "..." } in the body) to run it for the day you’re viewing. The response reports how many reservations were moved, plus the detail of each move and anything it could not place:

{
"success": true,
"date": "2026-07-04",
"reassigned": 2,
"scanned": 9,
"moves": [],
"unresolved": []
}

A price list sets a default_price_pence (the deposit/min-spend) that applies to every table, plus optional per-table overrides. POST /api/my-venues/:venueId/pricelists creates one (name required); PUT updates name/default; DELETE clears its overrides and detaches it from any access rules.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/pricelists" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Weekend","default_price_pence":5000}'
{ "success": true, "id": "pl_weekend" }

PUT /api/my-venues/:venueId/pricelists/:id/tables/:tableId sets a table’s price within a list. Send price_pence to set it, or null (or "") to clear the override so the list default applies again.

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/pricelists/pl_weekend/tables/tbl_12" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"price_pence":7500}'
{ "success": true }

PUT /api/my-venues/:venueId/pricelists/:id/tables (note: no :tableId) applies one price across many tables in a single call. Send table_ids and a price_pence to set, or price_pence as null (or "") to clear the override on each so the list default applies again. Only tables that belong to the venue are updated; the response reports how many were changed and how many were skipped.

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-venues/VENUE_ID/pricelists/pl_weekend/tables" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"table_ids":["tbl_12","tbl_13"],"price_pence":7500}'
{ "success": true, "changed": 2, "cleared": false, "skipped": 0 }

POST /api/my-venues/:venueId/tables/:id/dirty sets or clears a table’s “needs clearing” flag, shown on the reservations floorplan so staff know it isn’t ready for the next party yet.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/tables/tbl_12/dirty" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dirty":true}'
{ "success": true, "dirty": true }

Send {"dirty": false} to clear the flag once the table’s ready again.

If the venue has a till integration connected (for example Alliance iPos), these endpoints pull its sales into Sidedoor and match them to tables. :provider is the integration’s id, e.g. alliance.

POST .../integrations/:provider/backfill pulls till sales for a date range the automatic poll wouldn’t otherwise reach - useful right after connecting a till, or to fill a gap after an outage. Send a from and to date (inclusive, capped at 31 days); the same auto-matching the live poll uses then runs over that range.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/integrations/alliance/backfill" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"from":"2026-06-01","to":"2026-06-30"}'
{ "ok": true, "days": 30, "fetched": 412, "inserted": 390, "updated": 22, "errors": 0, "attached": 180 }

POST .../integrations/:provider/reconcile re-matches till sales to tables over a date range (also capped at 31 days), correcting mismatches as well as attaching new sales. It defaults to a dry run - it returns the plan without changing anything - so send "dryRun": false once you’re happy to apply it.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-venues/VENUE_ID/integrations/alliance/reconcile" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"from":"2026-06-01","to":"2026-06-07","dryRun":false}'

A dry run returns the plan without writing anything; passing dryRun: false applies it.