Availability Rules
Availability rules define when a provider is available for bookings. They use the iCalendar RRULE standard for recurrence patterns, making them flexible enough to handle any schedule.
Rule structure
Section titled “Rule structure”interface AvailabilityRuleInput { rrule: string; // iCalendar RRULE string startTime: string; // "HH:mm" format (e.g., "09:00") endTime: string; // "HH:mm" format (e.g., "17:00") timezone: string; // IANA timezone (e.g., "America/New_York") validFrom?: Date | null; // Rule starts applying from this date validUntil?: Date | null; // Rule stops applying after this date}Common patterns
Section titled “Common patterns”Standard business hours (Mon-Fri 9-5)
Section titled “Standard business hours (Mon-Fri 9-5)”{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York",}Split schedule (morning + afternoon with lunch break)
Section titled “Split schedule (morning + afternoon with lunch break)”Use two rules:
// Morning block{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "12:00", timezone: "America/New_York",}
// Afternoon block{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "13:00", endTime: "17:00", timezone: "America/New_York",}Weekend-only availability
Section titled “Weekend-only availability”{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=SA,SU", startTime: "10:00", endTime: "16:00", timezone: "Europe/London",}Seasonal availability (summer only)
Section titled “Seasonal availability (summer only)”{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York", validFrom: new Date("2026-06-01"), validUntil: new Date("2026-08-31"),}Exclude specific dates
Section titled “Exclude specific dates”Use EXDATE in the RRULE:
{ rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR\nEXDATE:20260325T000000Z,20260401T000000Z", startTime: "09:00", endTime: "17:00", timezone: "America/New_York",}Overrides
Section titled “Overrides”Overrides modify availability for specific dates without changing the underlying rules.
interface AvailabilityOverrideInput { date: Date; startTime?: string | null; // New start time, or null endTime?: string | null; // New end time, or null isUnavailable: boolean; // true = block the entire day}Block a day
Section titled “Block a day”{ date: new Date("2026-03-11"), isUnavailable: true }Shorten hours
Section titled “Shorten hours”{ date: new Date("2026-03-12"), startTime: "09:00", endTime: "12:00", isUnavailable: false,}Add extra hours
Section titled “Add extra hours”{ date: new Date("2026-03-14"), // A Saturday startTime: "10:00", endTime: "14:00", isUnavailable: false,}RRULE parsing
Section titled “RRULE parsing”The Booking Kit uses the rrule npm package for parsing. The parseRecurrence() function expands an RRULE into concrete date occurrences:
import { parseRecurrence } from "@thebookingkit/core";
const occurrences = parseRecurrence( "RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR", { start: new Date("2026-03-01"), end: new Date("2026-03-31") }, "09:00", "17:00");
// Returns: DateOccurrence[]// [// { date: "2026-03-02", startTime: "09:00", endTime: "17:00" }, // Monday// { date: "2026-03-04", startTime: "09:00", endTime: "17:00" }, // Wednesday// { date: "2026-03-06", startTime: "09:00", endTime: "17:00" }, // Friday// ...// ]Practical Examples
Section titled “Practical Examples”Creating common patterns
Section titled “Creating common patterns”import type { AvailabilityRuleInput } from "@thebookingkit/core";
// Mon-Fri 9am-5pm (standard business hours)const businessHours: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York",};
// Evenings only (5pm-9pm, Mon-Fri)const eveningsOnly: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "17:00", endTime: "21:00", timezone: "America/New_York",};
// Weekends only (Sat-Sun 10am-6pm)const weekendOnly: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=SA,SU", startTime: "10:00", endTime: "18:00", timezone: "Europe/London",};
// Specific time only (Tuesdays and Thursdays 2pm-4pm for consultations)const consultationHours: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=TU,TH", startTime: "14:00", endTime: "16:00", timezone: "America/Los_Angeles",};
// Daily recurring (every single day 9am-5pm)const dailyAvailability: AvailabilityRuleInput = { rrule: "RRULE:FREQ=DAILY", startTime: "09:00", endTime: "17:00", timezone: "America/Chicago",};Seasonal availability
Section titled “Seasonal availability”import type { AvailabilityRuleInput } from "@thebookingkit/core";
// Only available during summer (June 1 - August 31)const summerOnly: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York", validFrom: new Date("2026-06-01"), validUntil: new Date("2026-08-31"),};
// Available from March 15 onwards (no end date)const openingDate: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "10:00", endTime: "18:00", timezone: "Australia/Sydney", validFrom: new Date("2026-03-15"),};Split schedules with lunch breaks
Section titled “Split schedules with lunch breaks”For a provider with morning and afternoon hours, use two rules:
import type { AvailabilityRuleInput } from "@thebookingkit/core";
const morningShift: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "12:00", timezone: "Europe/Paris",};
const afternoonShift: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "13:00", endTime: "17:00", timezone: "Europe/Paris",};
// When computing slots, pass both rulesconst rules = [morningShift, afternoonShift];Using with slot computation
Section titled “Using with slot computation”import { getAvailableSlots, parseRecurrence } from "@thebookingkit/core";import type { AvailabilityRuleInput } from "@thebookingkit/core";
const rule: AvailabilityRuleInput = { rrule: "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York",};
// First, you can inspect what dates the rule coversconst occurrences = parseRecurrence( rule.rrule, { start: new Date("2026-03-01T00:00:00.000Z"), end: new Date("2026-03-31T23:59:59.999Z"), }, rule.startTime, rule.endTime);
console.log(`Rule covers ${occurrences.length} days in March`);
// Then compute available slotsconst slots = getAvailableSlots( [rule], [], [], { start: new Date("2026-03-09T00:00:00.000Z"), end: new Date("2026-03-13T23:59:59.999Z"), }, "America/New_York", { duration: 30 });
console.log(`${slots.length} slots available`);Database storage
Section titled “Database storage”Rules and overrides are stored in the availability_rules and availability_overrides tables. See Schema Overview for details.