Skip to content

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.

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
}
{
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",
}
{
rrule: "RRULE:FREQ=WEEKLY;BYDAY=SA,SU",
startTime: "10:00",
endTime: "16:00",
timezone: "Europe/London",
}
{
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"),
}

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 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
}
{ date: new Date("2026-03-11"), isUnavailable: true }
{
date: new Date("2026-03-12"),
startTime: "09:00",
endTime: "12:00",
isUnavailable: false,
}
{
date: new Date("2026-03-14"), // A Saturday
startTime: "10:00",
endTime: "14:00",
isUnavailable: false,
}

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
// ...
// ]
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",
};
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"),
};

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 rules
const rules = [morningShift, afternoonShift];
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 covers
const 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 slots
const 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`);

Rules and overrides are stored in the availability_rules and availability_overrides tables. See Schema Overview for details.