Skip to content

Embed & public widget endpoints

These are the public endpoints behind the Sidedoor widgets you embed on your own website - booking, events, vouchers and the all-in-one combo. They need no bearer token: a widget is identified by its venue (or event). For the operator-facing setup - enabling widgets, theming and grabbing the embed URL - see the widgets guide.

Method Path Purpose Auth
GET /api/public/venues/:venueId/booking-widget-config Booking widget config, keys and theme public
GET /api/public/venues/:venueId/availability Open slots for a date and party size public
GET /api/public/venues/:venueId/floorplan Floors and tables for guest table-pick public
POST /api/public/venues/:venueId/book Create a booking (may need payment) public
POST /api/public/venues/:venueId/book/finalize Finalise a deposit after payment public
GET /api/public/venues/:venueId/booking/:bookingId/qr Fetch the booking’s QR code public
GET /api/public/venues/:venueId/booking/:bookingId/gwallet Google Wallet pass for the booking public
GET /api/public/venues/:venueId/booking/:bookingId/apple Apple Wallet pass for the booking public
GET /api/public/venues/:venueId/booking/:bookingId/calendar.ics Add-to-calendar .ics file for the booking public
POST /api/public/venues/:venueId/waitlist Join the waitlist when a slot is full public
GET /api/public/venues/:venueId/events-widget Events widget listing public
GET /api/public/venues/:venueId/events-widget-config Events widget config and keys public
GET /api/public/events/:eventId/booking-options Bundles, ticket types and policy for an event public
GET /api/public/events/:eventId/promo Validate a promo code before booking public
POST /api/public/events/:eventId/create-intent Start an event booking public
POST /api/public/events/:eventId/finalize Finalise an event booking after payment public
GET /api/public/venues/:venueId/voucher-config Voucher widget config and keys public
POST /api/public/voucher-purchase/create-intent Start a gift-voucher purchase public
POST /api/public/voucher-purchase/finalize Finalise a voucher purchase, return codes public
GET /api/public/venues/:venueId/voucher/:code/gwallet Google Wallet pass for a purchased voucher public
GET /api/public/venues/:venueId/voucher/:code/apple Apple Wallet pass for a purchased voucher public
GET /api/public/venues/:venueId/guestlist-options Guest-list rates, surge and promo public
POST /api/public/venues/:venueId/guestlist-bookings Join the guest list (spends keys) session
GET /api/public/venues/:venueId/combo-widget-config All-in-one widget config public
GET /api/public/search Search venues and events across Sidedoor public
GET /api/public/venues/:venueId/experiences A venue’s branded experiences public
GET /api/public/venues/:venueId/reservation-tag-catalogue Reservation tags a guest can pick public
POST /api/public/venues/:venueId/book/quote Price a booking before making it public
POST /api/public/venues/:venueId/book/hold Hold a table during checkout public
POST /api/public/venues/:venueId/book/hold/confirm Convert a hold into a booking (no deposit) public
POST /api/public/venues/:venueId/book/hold/refresh Keep a checkout hold alive public
POST /api/public/venues/:venueId/book/hold/release Release a checkout hold public
POST /api/public/venues/:venueId/guestlist-hold Hold a guest-list spot during checkout public
POST /api/public/venues/:venueId/guestlist-hold/release Release a guest-list hold public
POST /api/public/events/:eventId/ticket-hold Hold free tickets during checkout public
POST /api/public/events/:eventId/ticket-hold/release Release a ticket hold public

GET /api/public/venues/:venueId/booking-widget-config returns the venue’s booking-widget settings, its theme, the display currency, and a Stripe publishable_key for the hosted card step. Fetch this first when bootstrapping a widget. Payment is handled by Sidedoor’s hosted widget - you never deal with card details or payment credentials yourself.

Terminal window
curl "https://thesidedoor.co/api/public/venues/VENUE_ID/booking-widget-config"
{
"currency": "GBP",
"venue": { "id": "VENUE_ID", "name": "The Blue Room" },
"widget": { "enabled": true, "theme_mode": "detailed", "accent_color": "#C0A060" },
"publishable_key": "pk_live_..."
}

A few endpoints aren’t tied to one widget’s flow - use them to build your own search box or to show a venue’s extras before a guest picks a slot.

GET /api/public/search searches venues and events across Sidedoor by q, with optional kind (venue/event), type, cuisine, when and group filters. It needs no venue id and is open to any site (CORS *).

Terminal window
curl "https://thesidedoor.co/api/public/search?q=cocktail&kind=venue"
{ "results": [{ "id": "ven_123", "name": "The Blue Room", "type": "venue" }] }

GET /api/public/venues/:venueId/experiences returns a venue’s branded experiences (e.g. “Sunday Roast”, “Tasting Menu”) for display before a guest picks a slot - each with a title, description, image_url and the days/times it runs.

Terminal window
curl "https://thesidedoor.co/api/public/venues/VENUE_ID/experiences"
{
"experiences": [
{ "id": "rul_roast", "title": "Sunday Roast", "description": "Three courses, served 12-4pm.", "image_url": "https://...", "days_of_week": [0], "time_from": "12:00", "time_to": "16:00" }
]
}

GET /api/public/venues/:venueId/reservation-tag-catalogue returns the reservation tags a guest can pick when booking a table (grouped by category), for a venue that lets guests add their own. An empty categories array just means the venue doesn’t offer any.

Terminal window
curl "https://thesidedoor.co/api/public/venues/VENUE_ID/reservation-tag-catalogue"
{ "categories": [{ "category": "Occasion", "tags": ["Birthday", "Anniversary"] }] }

GET /api/public/venues/:venueId/availability returns bookable slots for a date and party_size. Set type to tables or guestlist. It also returns the applicable rules, bundles and, when the requested time is full, the next available dates.

Terminal window
curl "https://thesidedoor.co/api/public/venues/VENUE_ID/availability?date=2026-07-18&party_size=4&type=tables"
{
"venue": { "id": "VENUE_ID", "name": "The Blue Room" },
"date": "2026-07-18",
"party_size": 4,
"type": "tables",
"slots": [
{ "time": "19:00", "access_rule_id": "rul_dinner", "available": true },
{ "time": "19:30", "access_rule_id": "rul_dinner", "available": true }
],
"party_too_large": false,
"next_available_dates": []
}

For a floorplan where the guest picks their own table, call GET /api/public/venues/:venueId/floorplan with the same date, time and party_size (plus the chosen rule_id); it returns { floors, tables } with per-table availability.

POST /api/public/venues/:venueId/book creates the booking. Pass the slot the guest chose (access_rule_id, rule_type, date, time, party_size), any bundle_selections, and the guest’s contact details.

The response depends on the venue’s payment policy. With no deposit you get { ok: true, booking_id, status }. When a deposit is required you get { requires_payment: true, booking_id } - Sidedoor’s hosted widget takes the guest through the secure card step, then you finalise (below).

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/book" \
-H "Content-Type: application/json" \
-d '{
"access_rule_id": "rul_dinner",
"rule_type": "tables",
"date": "2026-07-18",
"time": "19:00",
"party_size": 4,
"guest_name": "Sam Guest",
"guest_email": "sam@example.com",
"guest_phone": "+447700900123"
}'
{
"requires_payment": true,
"booking_id": "bkg_456"
}

Two optional steps can sit in front of /book for a table booking.

POST /api/public/venues/:venueId/book/quote prices a selection - the same body as /book (access_rule_id, rule_type, date, time, party_size, bundle_selections, plus any table/area/combo pick) without guest details - so you can show the real amount before the guest commits. It’s read-only: no booking or hold is created.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/book/quote" \
-H "Content-Type: application/json" \
-d '{"access_rule_id":"rul_dinner","rule_type":"tables","date":"2026-07-18","time":"19:00","party_size":4}'
{ "payment": { "kind": "hold", "amount_pence": 4000, "currency": "GBP" }, "table_id": "tbl_12", "combo_id": null }

POST /api/public/venues/:venueId/book/hold claims a specific free table for a short window while the guest finishes checkout, so another guest can’t take it from under them - only on venues whose table profile has checkout holds turned on; otherwise it returns { "held": false } and booking proceeds as normal. Pass the same slot fields; keep it alive with POST .../book/hold/refresh ({ hold_id }), and either convert it with POST .../book/hold/confirm ({ hold_id } - converts straight to a booking when no payment is due) or release it early with POST .../book/hold/release ({ hold_id }) if the guest abandons checkout. A paid booking instead carries the hold_id through to /book itself.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/book/hold" \
-H "Content-Type: application/json" \
-d '{"access_rule_id":"rul_dinner","date":"2026-07-18","time":"19:00","party_size":4}'
{ "held": true, "hold_id": "hld_1", "held_until": "2026-07-01T18:35:00Z", "hold_minutes": 5 }
POST /api/public/venues/:venueId/book/hold/confirm { "hold_id": "hld_1" }
{ "ok": true, "booking_id": "bkg_456", "status": "approved" }

Once the guest completes the card step in the Sidedoor widget, call POST /api/public/venues/:venueId/book/finalize with the booking_id. It re-checks the payment and either confirms the booking or releases it if payment did not complete. It is idempotent - safe to retry.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/book/finalize" \
-H "Content-Type: application/json" \
-d '{"booking_id":"bkg_456"}'
{ "ok": true, "booking_id": "bkg_456", "status": "confirmed" }

Once confirmed, fetch the door QR with GET /api/public/venues/:venueId/booking/:bookingId/qr. The code is short-lived - expires_in_ms tells you when to refresh it.

Terminal window
curl "https://thesidedoor.co/api/public/venues/VENUE_ID/booking/bkg_456/qr"
{ "qr_code": "data:image/png;base64,iVBOR...", "issued_at": 1751500000, "expires_in_ms": 60000 }

For a confirmed booking you can also offer a wallet pass or an add-to-calendar file. Like the QR route, these are keyed on the booking_id (the guest’s own capability token) so they need no bearer token:

  • GET /api/public/venues/:venueId/booking/:bookingId/gwallet - Google Wallet pass.
  • GET /api/public/venues/:venueId/booking/:bookingId/apple - Apple Wallet pass.
  • GET /api/public/venues/:venueId/booking/:bookingId/calendar.ics - an .ics file the guest can add to their calendar.

The same wallet pair exists for a purchased voucher, keyed on the voucher code: GET /api/public/venues/:venueId/voucher/:code/gwallet and .../apple.

When /availability reports a slot is full (for example party_too_large with next_available_dates), offer the waitlist instead. POST /api/public/venues/:venueId/waitlist takes the slot the guest wanted (access_rule_id, date, time, party_size) and their contact details.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/waitlist" \
-H "Content-Type: application/json" \
-d '{
"access_rule_id": "rul_dinner",
"date": "2026-07-18",
"time": "19:00",
"party_size": 4,
"guest_name": "Sam Guest",
"guest_email": "sam@example.com"
}'

List a venue’s what’s-on with GET /api/public/venues/:venueId/events-widget (and .../events-widget-config for keys and theme). For a chosen event, read GET /api/public/events/:eventId/booking-options to get bundles, ticket types and policy, then book with POST /api/public/events/:eventId/create-intent.

The create-intent body carries the selection ({ kind, ticket_type_id, quantity, party_size }) and guest details. It returns { free, booking_id }, { requires_payment, ... } or { requires_confirmation }. When payment is needed, the Sidedoor widget takes the guest through the card step; then call POST /api/public/events/:eventId/finalize with the returned payment_intent_id.

To validate a promo code before booking, call GET /api/public/events/:eventId/promo?code=CODE. It returns { applied: true, ... } with the discount type and amount when the code is valid, or { applied: false, error } when it is not.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/events/EVENT_ID/create-intent" \
-H "Content-Type: application/json" \
-d '{
"selection": { "kind": "ticket", "ticket_type_id": "tkt_ga", "quantity": 2 },
"guest_name": "Sam Guest",
"guest_email": "sam@example.com"
}'
{ "requires_payment": true, "booking_id": "evb_789", "payment_intent_id": "pi_3Nxyz" }

For a free ticket type, POST /api/public/events/:eventId/ticket-hold claims the requested quantity of a ticket_type_id for a short window while the guest finishes checkout, so they don’t lose them to another guest. Release it early with POST .../ticket-hold/release ({ hold_id }) if the guest abandons checkout; otherwise it’s released automatically on expiry.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/events/EVENT_ID/ticket-hold" \
-H "Content-Type: application/json" \
-d '{"ticket_type_id":"tkt_ga","quantity":2}'
{ "held": true, "hold_id": "hld_evt_1", "held_until": "2026-07-01T18:35:00Z", "hold_minutes": 5 }

Read GET /api/public/venues/:venueId/voucher-config for settings and keys. Start a purchase with POST /api/public/voucher-purchase/create-intent (amount, quantity, delivery and purchaser details); once the guest completes the card step in the Sidedoor widget, call POST /api/public/voucher-purchase/finalize with the intent_id to receive the issued voucher codes.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/voucher-purchase/create-intent" \
-H "Content-Type: application/json" \
-d '{
"venue_id": "VENUE_ID",
"amount_pence": 5000,
"quantity": 1,
"delivery": "recipient",
"recipient_name": "Alex",
"recipient_email": "alex@example.com",
"purchaser_name": "Sam Guest",
"purchaser_email": "sam@example.com"
}'
{ "intent_id": "vin_321" }

Once the card step is complete, finalise:

POST /api/public/voucher-purchase/finalize { "intent_id": "vin_321" }
{
"success": true,
"delivery": "recipient",
"vouchers": [
{ "code": "GIFT-4KQ2-9XTP", "amount_pence": 5000, "expires_at": "2027-07-03" }
]
}

Read GET /api/public/venues/:venueId/guestlist-options for the rate, any surge and promo eligibility, then join with POST /api/public/venues/:venueId/guestlist-bookings. This one needs a session - the guest must be signed in, because it spends guest keys rather than taking a card payment. The body is { rule_id, date, party_size, option_kind, promo_code }.

{ "success": true, "booking_id": "bkg_902", "status": "approved", "keys_spent": 2, "auto_approved": true }

POST /api/public/venues/:venueId/guestlist-hold claims a guest-list spot for a short window while the guest finishes checkout, the same pattern as the table checkout hold above. Pass the slot (rule_id, date, party_size); release it early with POST .../guestlist-hold/release ({ hold_id }) if the guest abandons checkout, otherwise it’s released automatically on expiry. POST /guestlist-bookings carries the hold_id through to convert it.

Terminal window
curl -X POST "https://thesidedoor.co/api/public/venues/VENUE_ID/guestlist-hold" \
-H "Content-Type: application/json" \
-d '{"rule_id":"rul_gl","date":"2026-07-18","party_size":4}'
{ "held": true, "hold_id": "hld_gl_1", "held_until": "2026-07-01T18:35:00Z", "hold_minutes": 5 }

GET /api/public/venues/:venueId/combo-widget-config returns which flows are enabled (bookings, events, vouchers) plus the links the combo widget needs to route into each of the flows above.

{
"enabled": { "bookings": true, "events": true, "vouchers": false },
"links": { "bookings": "...", "events": "..." }
}