Recurring Bookings
Recurring bookings let customers book a series of appointments at a regular cadence — weekly therapy sessions, biweekly coaching calls, monthly check-ups.
Creating a series
Section titled “Creating a series”import { generateOccurrences } from "@thebookingkit/core";import type { RecurringSeriesInput, RecurringOccurrence } from "@thebookingkit/core";
const input: RecurringSeriesInput = { startsAt: new Date("2026-03-10T14:00:00.000Z"), // First appointment (UTC) durationMinutes: 30, frequency: "weekly", count: 8, // Generate 8 occurrences};
const occurrences: RecurringOccurrence[] = generateOccurrences(input);
console.log(occurrences);// Output:// [// { index: 0, startsAt: 2026-03-10T14:00:00Z, endsAt: 2026-03-10T14:30:00Z },// { index: 1, startsAt: 2026-03-17T14:00:00Z, endsAt: 2026-03-17T14:30:00Z },// { index: 2, startsAt: 2026-03-24T14:00:00Z, endsAt: 2026-03-24T14:30:00Z },// { index: 3, startsAt: 2026-03-31T14:00:00Z, endsAt: 2026-03-31T14:30:00Z },// ...8 total occurrences// ]Different frequencies:
import { generateOccurrences } from "@thebookingkit/core";
// Weekly: every Tuesday at 2pm UTC, 6 sessionsconst weekly = generateOccurrences({ startsAt: new Date("2026-03-10T14:00:00.000Z"), durationMinutes: 60, frequency: "weekly", count: 6,});
// Biweekly: every other week, 4 sessionsconst biweekly = generateOccurrences({ startsAt: new Date("2026-03-10T14:00:00.000Z"), durationMinutes: 60, frequency: "biweekly", count: 4,});
// Monthly: same day of month, 3 sessionsconst monthly = generateOccurrences({ startsAt: new Date("2026-03-10T14:00:00.000Z"), durationMinutes: 60, frequency: "monthly", count: 3,});Frequencies
Section titled “Frequencies”| Frequency | Description | Example |
|---|---|---|
weekly | Same day and time every week | Every Tuesday at 2pm |
biweekly | Every two weeks | Every other Tuesday at 2pm |
monthly | Same day of month | 10th of every month at 2pm |
Availability checking
Section titled “Availability checking”import { checkRecurringAvailability } from "@thebookingkit/core";import type { AvailabilityRuleInput, BookingInput } from "@thebookingkit/core";
// First, generate the series occurrencesconst occurrences = generateOccurrences({ startsAt: new Date("2026-03-10T14:00:00.000Z"), durationMinutes: 30, frequency: "weekly", count: 8,});
// Provider's availability rules (Monday-Friday 9am-5pm Eastern)const rules: AvailabilityRuleInput[] = [ { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York", },];
// Existing bookings that might conflictconst existingBookings: BookingInput[] = [];
// Check if all occurrences can be bookedconst result = checkRecurringAvailability( occurrences, rules, [], // overrides existingBookings);
if (result.allAvailable) { console.log("All 8 sessions are available!");} else { console.log(`${result.conflicts.length} sessions have conflicts:`); result.conflicts.forEach(index => { console.log(` - Session ${index + 1}: ${occurrences[index].startsAt}`); });}Customer can choose to book only available occurrences:
import { generateOccurrences, checkRecurringAvailability } from "@thebookingkit/core";
const occurrences = generateOccurrences({ startsAt: new Date("2026-03-10T14:00:00.000Z"), durationMinutes: 30, frequency: "weekly", count: 8,});
const availability = checkRecurringAvailability( occurrences, rules, overrides, existingBookings);
// Show customer what's availableconst availableOccurrences = occurrences.filter( occ => !availability.conflicts.includes(occ.index));
console.log(`${availableOccurrences.length} of ${occurrences.length} sessions available`);// Output: "6 of 8 sessions available"
// Customer decides to book only the available onesconst bookingsToCreate = availableOccurrences.map(occ => ({ startsAt: occ.startsAt, endsAt: occ.endsAt, occurrenceIndex: occ.index,}));Cancelling future occurrences
Section titled “Cancelling future occurrences”import { cancelFutureOccurrences } from "@thebookingkit/core";import type { SeriesBooking } from "@thebookingkit/core";
// Get all bookings in the seriesconst seriesBookings: SeriesBooking[] = [ { id: "booking-1", index: 0, startsAt: new Date("2026-03-10T14:00:00.000Z"), endsAt: new Date("2026-03-10T14:30:00.000Z"), status: "confirmed", }, { id: "booking-2", index: 1, startsAt: new Date("2026-03-17T14:00:00.000Z"), endsAt: new Date("2026-03-17T14:30:00.000Z"), status: "confirmed", }, { id: "booking-3", index: 2, startsAt: new Date("2026-03-24T14:00:00.000Z"), endsAt: new Date("2026-03-24T14:30:00.000Z"), status: "confirmed", }, { id: "booking-4", index: 3, startsAt: new Date("2026-03-31T14:00:00.000Z"), endsAt: new Date("2026-03-31T14:30:00.000Z"), status: "confirmed", },];
// Customer cancels all sessions from April 1 onwardconst result = cancelFutureOccurrences( seriesBookings, new Date("2026-04-01T00:00:00.000Z"));
console.log(result);// {// cancelledIds: ["booking-4"], // index 3 is >= April 1// skippedIds: [],// }// Sessions 0-2 (March) remain; session 3 (March 31) is on boundaryUI component
Section titled “UI component”import { RecurringBookingPicker } from "./components/recurring-booking-picker";
<RecurringBookingPicker frequencies={["weekly", "biweekly", "monthly"]} maxOccurrences={12} occurrences={generatedOccurrences} onFrequencyChange={handleFrequencyChange} onCountChange={handleCountChange}/>