Skip to content

JavaScript API

For non-React contexts (server-side, mobile, automation scripts) the package exports two typed clients:

  • createBookingClient — generic Calendly-style endpoints
  • createRestaurantBookingClient — restaurant-specific endpoints (extends the generic one)

Both clients are pure fetch wrappers — no React, no DOM. They run anywhere fetch exists (Node 18+, Bun, Deno, browsers, edge runtimes).

createBookingClient

ts
import { createBookingClient } from "@periscaleai/booking-widget/client";

const booking = createBookingClient(
  "https://api.periscale.app/api/v1/business/website/booking",
  { apiKey: "sb_live_xxx" },
);

Methods

MethodReturns
getConfig()Result<BookingConfig> — operating hours, cancellation policy, timezone, etc.
getServices()Result<BookingService[]> — bookable services with duration & price.
getSlots(date, serviceId?)Result<SlotsResponse> — available time slots for a given YYYY-MM-DD.
createAppointment(body)Result<Appointment> — create a booking.
getMyAppointments(phone)Result<Appointment[]> — phone-number lookup.
cancelAppointment(id, reason?)Result<Appointment> — customer cancellation.

Result<T> shape

Every method returns a discriminated union — never throws on HTTP errors:

ts
type Result<T> =
  | { ok: true; data: T }
  | { ok: false; error: string };
ts
const slots = await booking.getSlots("2026-05-04");
if (!slots.ok) {
  console.error("Could not load slots:", slots.error);
  return;
}
slots.data.slots.forEach((s) => console.log(s.start_time, s.available));

Example: list and book

ts
import { createBookingClient } from "@periscaleai/booking-widget/client";

const client = createBookingClient(
  "https://api.periscale.app/api/v1/business/website/booking",
  { apiKey: process.env.PERISCALE_API_KEY! },
);

const config = await client.getConfig();
const slots = await client.getSlots("2026-05-04");
if (slots.ok) {
  const open = slots.data.slots.find((s) => s.available);
  if (open) {
    await client.createAppointment({
      customer_name: "Sarah Tanaka",
      customer_phone: "+6591234567",
      customer_email: "sarah@example.com",
      date: "2026-05-04",
      start_time: open.start_time,
      customer_notes: "First-timer",
    });
  }
}

createRestaurantBookingClient

ts
import { createRestaurantBookingClient } from "@periscaleai/booking-widget/restaurant/client";

const restaurant = createRestaurantBookingClient({
  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",
});

Methods

It includes everything from the generic client, plus:

MethodReturns
getAvailableTables(date, startTime, partySize, serviceId?, branchId?)Result<AvailableTablesResponse> — tables available for the chosen slot + party size, grouped by section.
createReservation(body)Result<Reservation> — Appointment + RestaurantReservation atomically.
getMyReservations(phone)Result<Reservation[]> — phone-number lookup with party + table info.
cancelReservation(id, reason?)Result<void> — customer cancellation.

Example: server-side reservation creation

ts
import { createRestaurantBookingClient } from "@periscaleai/booking-widget/restaurant/client";

const r = createRestaurantBookingClient({
  bookingApiBase: process.env.PERISCALE_BOOKING_BASE!,
  reservationApiBase: process.env.PERISCALE_RESERVATION_BASE!,
  apiKey: process.env.PERISCALE_API_KEY!,
});

// Step 1: find a table
const tables = await r.getAvailableTables("2026-05-04", "19:00", 4);
if (!tables.ok) throw new Error(tables.error);

// Step 2: create the reservation
const reservation = await r.createReservation({
  customer_name: "Sarah Tanaka",
  customer_phone: "+6591234567",
  customer_email: "sarah@example.com",
  party_size: 4,
  table_id: tables.data.tables[0]?.id,
  date: "2026-05-04",
  start_time: "19:00",
  customer_notes: "Anniversary",
});

if (reservation.ok) {
  console.log("Reservation ID:", reservation.data.id);
}

Types

Granular type-only imports, useful when you don't want the runtime client:

ts
import type {
  Appointment, AppointmentStatus,
  BookingConfig, BookingService,
  CreateAppointmentRequest, SlotsResponse, TimeSlot,
} from "@periscaleai/booking-widget/types";

import type {
  Reservation, RestaurantTable,
  AvailableTablesResponse, CreateReservationRequest,
} from "@periscaleai/booking-widget/restaurant/types";

Subpath summary

SubpathExports
@periscaleai/booking-widgetBookingWidget, generic types & client
@periscaleai/booking-widget/blocksAll step components + StepIndicator / TabBar / BackButton
@periscaleai/booking-widget/restaurantRestaurantBookingWidget, restaurant components + client
@periscaleai/booking-widget/typesGeneric types only
@periscaleai/booking-widget/clientGeneric client only
@periscaleai/booking-widget/restaurant/typesRestaurant types only
@periscaleai/booking-widget/restaurant/clientRestaurant client only

© Periscale