JavaScript API
For non-React contexts (server-side, mobile, automation scripts) the package exports two typed clients:
createBookingClient— generic Calendly-style endpointscreateRestaurantBookingClient— 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
| Method | Returns |
|---|---|
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:
| Method | Returns |
|---|---|
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
| Subpath | Exports |
|---|---|
@periscaleai/booking-widget | BookingWidget, generic types & client |
@periscaleai/booking-widget/blocks | All step components + StepIndicator / TabBar / BackButton |
@periscaleai/booking-widget/restaurant | RestaurantBookingWidget, restaurant components + client |
@periscaleai/booking-widget/types | Generic types only |
@periscaleai/booking-widget/client | Generic client only |
@periscaleai/booking-widget/restaurant/types | Restaurant types only |
@periscaleai/booking-widget/restaurant/client | Restaurant client only |