Skip to content

Restaurant Flavor

The restaurant flavor extends the generic Calendly-style flow with two extra steps the host stand actually cares about: how many guests and which table.

tsx
import { RestaurantBookingWidget } from "@periscaleai/booking-widget/restaurant";

<RestaurantBookingWidget
  bookingApiBase="https://api.periscale.app/api/v1/business/website/booking"
  reservationApiBase="https://api.periscale.app/api/v1/business/website/restaurant-booking"
  apiKey="sb_live_xxx"
  largePartyContactPhone="+65 8910 8835"
  maxOnlinePartySize={8}
/>

Flow

  1. Date — calendar of dates within max_advance_booking_days.
  2. Time — slot grid for the selected date.
  3. Party — chip selector (1–maxOnlinePartySize). Guests above the cap see a "call us" CTA.
  4. Table — only tables with capacity >= partySize and no overlapping non-cancelled reservation are shown. Grouped by section (Main, Patio, Bar, …) when the section field is set.
  5. Details — name, phone, email, special requests.
  6. Confirm — confirmation screen with reservation ID, party size, and table number; confirmation email is sent (party size + table appended automatically).

The "My Reservations" tab works exactly like the generic widget's "My Bookings" — phone-number lookup, with party + table shown on each card.

Props

RestaurantBookingWidgetProps extends both BookingClientOptions (so apiKey flows through) and RestaurantClientBases.

PropTypeRequiredDescription
bookingApiBasestringGeneric booking endpoint base. The widget reuses getConfig / getServices / getSlots from this.
reservationApiBasestringRestaurant endpoint base — /tables/, /reservations/, /my-reservations/.
apiKeystring✅ on third-party sitessb_live_… widget key. Appended as ?api_key=… on every request.
branchIdnumberoptionalPin reservations to a specific branch. Default: backend picks the first active branch for your business.
largePartyContactPhonestringoptionalPhone number shown on the party-size step for groups above the online cap.
maxOnlinePartySizenumberoptional, default 8Largest party that can be booked online. Anything bigger routes to the phone CTA.
defaultTab"reserve" | "my-reservations"optional, default "reserve"Which tab is active on first paint.
classNamestringoptionalExtra Tailwind classes on the outer container.
onBookingComplete(reservation: Reservation) => voidoptionalFires after a successful reservation creation. Use for analytics or redirects.

Sub-components

If you need a different shell but want to keep our pickers, every step is exported:

tsx
import {
  PartySizePicker,
  TablePicker,
  ReservationDetailsForm,
  ReservationConfirmation,
  MyReservations,
  createRestaurantBookingClient,
} from "@periscaleai/booking-widget/restaurant";

Compose them with the building blocks (CalendarPicker, TimeSlotGrid, StepIndicator, TabBar).

Backend setup

The restaurant flavor needs the Periscale restaurant Django app enabled and:

  • A Branch with is_active = true.
  • Several Table rows under that branch (with capacity set; section is optional but improves the picker UX).
  • The BookingConfig for the business has is_enabled = true and weekly BusinessAvailability rows for the days you accept reservations.

The widget calls these endpoints (under reservationApiBase):

MethodPathPurpose
GET/tables/?date=&start_time=&party_size=[&service_id=&branch_id=]Tables available for a chosen slot + party size.
POST/reservations/Create a reservation (Appointment + RestaurantReservation sidecar).
GET/my-reservations/?phone=Phone-number lookup.
POST/reservations/{id}/cancel/Customer-side cancel, respects cancellation_policy_hours.

Confirmation email

The generic booking confirmation email is sent automatically. The restaurant app registers an email-extension callback so the body includes:

Party size: 4
Table: Patio 7

These lines only appear when a RestaurantReservation is attached to the appointment — non-restaurant verticals get the plain template.

© Periscale