Skip to main content

Availability rules

As the name suggests, availability rules are used to define the availability of a service. They are used to define the time slots in which the service can be booked.

{
// Event duration (legacy - use availabilitySchedule instead)
"duration": "string",
// Start frequency (legacy - use availabilitySchedule instead)
"step": "string",
// Schedule - Legacy approach
"repeatingAvailability": {
"timeZone": "string",
"weekly": {
"[DAY_OF_THE_WEEK]": [
{
"start": "string",
"end": "string"
}
]
}
},
// Schedule - Recommended approach (takes precedence over repeatingAvailability)
"availabilitySchedule": {
"schedule": {
"defaultDurations": { "type": "discrete", "values": ["PT1H"] },
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "09:00",
"duration": "PT8H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]
}
}
]
}
},
// Maximum concurrent bookings
"maxConcurrentBookings": 0,
// How early and how late a booking can be made, and how that time is counted
"notice": {},
// Deprecated, use "notice" instead
"minBookingNotice": "string",
// Deprecated, use "notice" instead
"maxBookingNotice": "string",
// Time margin after the booking
"beforeBuffer": "string",
// Time margin before the booking
"afterBuffer": "string",
// Allows connecting external calendars and creating or checking availability in them...
"thirdPartyCalendars": {},
// Allows manually configuring intervals where availability will not be offered...
"busyIntervals": [],
}

Basic rules​

Duration (duration)​

The duration field allows you to configure the duration of the event in hours and minutes. The duration is specified in standard ISO9601 format

Examples:

  • An interval of one hour: PT1H
  • An interval of one hour and 30 minutes: PT1H30M
  • An interval of 20 minutes: PT20M

Start frequency (step)​

Regardless of the duration of the services, we may want them to start at a certain time.

The step field allows you to configure how often time slots are generated in which the event can be booked.

Example: Duration 1h Step 30m​

{
duration: 'PT1H',
step: 'PT30M',
}

If we create an event of 1h with a step of 30m the following slots will be generated:

  • 09:00 - 10:00
  • 09:30 - 10:30
  • 10:00 - 11:00
  • 10:30 - 11:30

Example: Duration 1h Step 20m​

{
duration: 'PT1H',
step: 'PT20M',
}

If we create an event of 1h with a step of 20m the following slots will be generated:

  • 09:00 - 10:00
  • 09:20 - 10:20
  • 09:40 - 10:40
  • 10:00 - 11:00
  • 10:20 - 11:20
  • 10:40 - 11:40

Schedule (repeatingAvailability)​

Legacy Field

The repeatingAvailability field is legacy and will be replaced by the availabilitySchedule field in future versions of the API.

We recommend using availabilitySchedule for all new implementations. See the iCal-Based Availability Schedule section below for the modern approach, which supports:

  • Cross-midnight availability
  • Multi-day events
  • One-off specific dates
  • Complex recurrence patterns
  • Multiple duration options
  • Per-window durations
  • Exception dates

Allows you to configure the hours in which slots will be generated regularly.

The schedule object consists of two main properties, the time zone and the weekly periodicity.

Example: Working days from 09:00 to 18:00​

Legacy approach (repeatingAvailability):

{
timeZone: 'Europe/Madrid',
weekly: {
SUNDAY: [],
MONDAY: [{ start: '09:00', end: '18:00' }],
TUESDAY: [{ start: '09:00', end: '18:00' }],
WEDNESDAY: [{ start: '09:00', end: '18:00' }],
THURSDAY: [{ start: '09:00', end: '18:00' }],
FRIDAY: [{ start: '09:00', end: '18:00' }],
SATURDAY: [],
}
}

Recommended approach (availabilitySchedule):

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT1H"]
},
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "09:00",
"duration": "PT9H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
}
]
}
}
}

To specify breaks, for example the corresponding to lunch time, it is enough to add another interval to the corresponding day.

Example: Working days from 09:00 to 14:00 and from 16:00 to 18:00​

Legacy approach (repeatingAvailability):

{
timeZone: 'Europe/Madrid',
weekly: {
SUNDAY: [],
MONDAY: [{ start: '09:00', end: '14:00' }, { start: '16:00', end: '18:00' }],
TUESDAY: [{ start: '09:00', end: '14:00' }, { start: '16:00', end: '18:00' }],
WEDNESDAY: [{ start: '09:00', end: '14:00' }, { start: '16:00', end: '18:00' }],
THURSDAY: [{ start: '09:00', end: '14:00' }, { start: '16:00', end: '18:00' }],
FRIDAY: [{ start: '09:00', end: '14:00' }, { start: '16:00', end: '18:00' }],
SATURDAY: [],
}
}

Recommended approach (availabilitySchedule):

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT1H"]
},
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "09:00",
"duration": "PT5H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
},
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "16:00",
"duration": "PT2H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
}
]
}
}
}

Advanced rules​

Buffers between bookings​

Sometimes we want to block a time span before and after the events. An example is a doctor who wants to have 10 minutes before each appointment to read the patient's data calmly or a beauty clinic that has to disinfect the cabins after each session.

  • beforeBuffer: Allows you to specify a time margin before the events in duration format.
  • afterBuffer Allows you to specify this time margin after the events in duration format.

Example: A service that has to have 10 minutes before and 20 minutes after each appointment.​

{
// 10 minutes before
beforeBuffer: "PT10M",
// 20 minutes after.
afterBuffer: "PT20M",
}

Example: A service that has to have 10 minutes before and 20 minutes after each appointment.​

{
// 10 minutes before
beforeBuffer: "PT10M",
// 20 minutes after.
afterBuffer: "PT20M",
}

Maximum and minimum booking notice​

The notice option restricts how early and how late a service can be booked. Each side declares how much notice there is and how that amount is counted, so the same amount can mean natural time, working hours or working days.

{
notice: {
// The minimum has to be booked 24h in advance, counting every hour.
min: { amount: "PT24H" },
// The maximum is 7 natural days ahead.
max: { amount: "P7D" },
},
}

Bookings outside the resulting window are not offered and cannot be created. This is useful to avoid last minute bookings, or bookings too far in advance.

Counting modes​

countingMeaning
calendarTime (default)Natural time: every hour counts. No calendar needed.
businessTimeThe amount is consumed only inside the calendar, so PT4H means four working hours.
businessDaysWhole counting days are counted, so P2D means two working days, and the target day belongs entirely to the allowed window. The amount must be a whole number of days.

The two business modes need a calendar, which says which time counts. Everything outside it is skipped instead of consumed. The calendar is shared by min and max, and each side opts in separately, so enabling working days for the minimum never changes the meaning of the maximum.

Example: two working days of notice, skipping weekends and two holidays​

{
notice: {
calendar: {
timeZone: "Europe/Madrid",
countingDays: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"],
exclusions: { dates: ["2026-12-06", "2026-12-08"] },
},
min: { amount: "P2D", counting: "businessDays" },
},
}

Someone opening the booking page on Friday 4 December at 16:00 gets their first slot on Wednesday 9 December, the whole day: Saturday, Sunday and the holiday on Tuesday 8 do not consume notice. The 6th falls on a Sunday, which already did not count, so listing it changes nothing — a holiday list can be dumped in as it is.

A calendar only decides how the notice is measured, never when the service is open. If there is published availability on an excluded date, that date is still bookable.

Counting hours​

businessTime can be narrowed to a time of day per weekday, for the "four working hours of notice" case. A counting day without an entry counts as a whole day.

{
notice: {
calendar: {
timeZone: "Europe/Madrid",
countingDays: ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"],
countingHours: {
MONDAY: [{ start: "09:00", end: "18:00" }],
FRIDAY: [{ start: "09:00", end: "15:00" }],
},
},
min: { amount: "PT4H", counting: "businessTime" },
},
}

Same-day cutoff​

A minimum counted in businessDays accepts a cutoffTime: an attempt later than that time of day starts counting from the next counting day. With cutoffTime: "12:00" and one day of notice, a request at 10:00 opens the next counting day, and a request at 13:00 opens the one after.

Deprecated: minBookingNotice and maxBookingNotice​

The former minBookingNotice and maxBookingNotice fields only expressed an amount of natural time and are deprecated in favour of notice. They are still accepted on write and still returned on read, carrying the amount without the counting mode.

When a write carries both, notice is used. Changing a deprecated field while also sending notice is a conflict: the request is logged while the remaining usage of the deprecated fields is measured, and once they stop being written it is rejected with a 400 rather than silently dropping the change.

Max number of bookings per slot​

Allows you to configure the maximum number of bookings that can be made in each available slot.

Example: A psychologist who can only see one patient at a time:​

{
// 1 concurrent booking per slot is allowed.
"maxConcurrentBookings": 1,
}

Example: A spinning class with 10 bikes:​

{
// 10 concurrent bookings per slot are allowed.
"maxConcurrentBookings": 10,
}

Limit of bookings per time unit. (maxBookingsPerTimeUnit)​

Allows to configure the maximum number of bookings that can be made in a given time period. It contains an array of limits formed by the following fields:

  • perHour: Maximum number of bookings per hour.
  • perDay: Maximum number of bookings per day.
  • perWeek: Maximum number of bookings per week.
  • perMonth: Maximum number of bookings per month.
Important

It is considered that an event belongs to the period if its start date or its end date is within the period. Time periods are calculated according to the time zone specified in the TimeZone field of the service. If this field is not configured, UTC is used.

Example: A service that allows a maximum of 10 bookings per hour:​

maxBookingsPerTimeUnit: {
byHour: 10,
}

### Example: Maximum 3 bookings per day, 15 per week or 30 per month.

{
maxBookingsPerTimeUnit: {
byDay: 3,
byWeek: 15,
byMonth: 30,
}
}

Units​

In certain types of bookings the maxConcurrentBookings field is not enough if we want to represent situations where in each booking a variable number of bookable objects can be specified.

Example: A show that has 100 seats and for each reservation a minimum of 1 seat and a maximum of 5 can be reserved:​

{
"availableUnits": 20,
"minUnitsPerBooking": 5,
"maxUnitsPerBooking": 20,
}

iCal-Based Availability Schedule​

Recommended

The availabilitySchedule field is the recommended way to define availability. It provides a powerful, flexible system using iCal (RFC 5545) internally, supporting advanced scheduling scenarios that weren't possible with the legacy repeatingAvailability field.

The iCal-based availability schedule system allows you to define complex availability patterns including:

  • Cross-midnight availability (e.g., bar open 10pm-2am)
  • Multi-day events (e.g., weekend workshops)
  • One-off specific dates (e.g., special holiday hours)
  • Complex recurrence patterns (e.g., first Monday of each month)
  • Multiple duration options (e.g., offer 30min, 1h, or 2h sessions)
  • Per-window durations (e.g., 2h workshops on Mondays, 30min calls on Fridays)
  • Exception dates (e.g., exclude holidays)

Core Concepts​

Availability Windows​

An availability window defines a time period when bookings are possible. There are two types:

  1. Recurring Windows: Repeat on a schedule (daily, weekly, monthly, yearly)

    • Defined by a timezone, start time, duration, and recurrence pattern
    • Example: "Every Monday-Friday, 9am-5pm in America/New_York"
  2. One-Off Windows: Specific date/time ranges

    • Defined by explicit start and end datetimes
    • Example: "December 25, 2024, 10am-2pm UTC"

Duration Options​

Each window (or the entire schedule) can specify what durations are allowed:

  1. Discrete Durations: A fixed list of allowed durations

    • Example: ["PT30M", "PT1H"] - only 30 minutes or 1 hour
  2. Range Durations: Any duration within a range with a step

    • Example: min: "PT1H", max: "PT4H", step: "PT15M" - any duration from 1h to 4h in 15-minute increments
  3. Fit to Window: The duration must exactly match the window size

    • Example: A 3-hour window only allows 3-hour bookings

Recurrence Patterns​

Recurring windows use recurrence rules to define when they repeat:

  • Frequency: DAILY, WEEKLY, MONTHLY, or YEARLY
  • Interval: Repeat every N periods (e.g., every 2 weeks)
  • Days of Week: For weekly patterns (e.g., Monday, Wednesday, Friday)
  • Days of Month: For monthly patterns (e.g., 1st and 15th)
  • Months of Year: For yearly patterns
  • Until/Count: Optional end date or maximum occurrences

Basic Structure​

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT30M", "PT1H"]
},
"slotStep": "PT30M",
"windows": [
{
"type": "recurring",
"timeZone": "America/New_York",
"startTime": "09:00",
"duration": "PT8H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
}
],
"exceptions": []
}
}
}

Duration Options Explained​

Discrete Durations​

Use when you want to offer specific, fixed durations:

{
"defaultDurations": {
"type": "discrete",
"values": ["PT30M", "PT1H", "PT2H"]
}
}

This allows bookings of exactly 30 minutes, 1 hour, or 2 hours.

Range Durations​

Use when you want flexibility within a range:

{
"defaultDurations": {
"type": "range",
"min": "PT1H",
"max": "PT4H",
"step": "PT15M"
}
}

This allows any duration from 1 hour to 4 hours, in 15-minute increments (1h, 1h15m, 1h30m, ..., 4h).

Fit to Window​

Use when the booking must fill the entire window:

{
"durations": {
"type": "fit"
}
}

This is typically used for one-off windows where the duration must match the window exactly.

Use Case Examples​

Example 1: Standard Business Hours​

Scenario: Available Monday-Friday 9am-5pm for 30min or 1h meetings

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT30M", "PT1H"]
},
"windows": [
{
"type": "recurring",
"timeZone": "America/New_York",
"startTime": "09:00",
"duration": "PT8H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
}
]
}
}
}

Availability Response (GET /v1/event-types/{id}/availability):

{
"timeSlots": [
{
"start": "2024-01-15T14:00:00Z",
"end": "2024-01-15T14:30:00Z",
"score": 1
},
{
"start": "2024-01-15T14:00:00Z",
"end": "2024-01-15T15:00:00Z",
"score": 1
},
{
"start": "2024-01-15T14:30:00Z",
"end": "2024-01-15T15:00:00Z",
"score": 1
}
],
"durationOptions": {
"type": "discrete",
"values": ["PT30M", "PT1H"]
}
}

Example 2: Cross-Midnight Availability​

Scenario: Available Friday and Saturday 10pm-2am for 2h sessions that span midnight

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT2H"]
},
"slotStep": "PT1H",
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "22:00",
"duration": "PT4H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": ["FRIDAY", "SATURDAY"]
}
}
]
}
}
}

This creates slots like:

  • Friday 22:00-00:00 (spans midnight)
  • Friday 23:00-01:00 (spans midnight)
  • Saturday 22:00-00:00 (spans midnight)
  • Saturday 23:00-01:00 (spans midnight)

Availability Response (with ?duration=PT2H):

{
"timeSlots": [
{
"start": "2024-01-19T22:00:00+01:00",
"end": "2024-01-20T00:00:00+01:00",
"score": 1
},
{
"start": "2024-01-19T23:00:00+01:00",
"end": "2024-01-20T01:00:00+01:00",
"score": 1
}
],
"durationOptions": {
"type": "discrete",
"values": ["PT2H"]
},
"selectedDuration": "PT2H"
}

Example 3: Multi-Day Event​

Scenario: Weekend workshop Friday 6pm through Sunday 3pm, 3h sessions only

{
"availabilitySchedule": {
"schedule": {
"windows": [
{
"type": "oneOff",
"start": {
"dateTime": "2024-03-15T18:00:00+00:00",
"timeZone": "Europe/London"
},
"end": {
"dateTime": "2024-03-17T15:00:00+00:00",
"timeZone": "Europe/London"
},
"durations": {
"type": "discrete",
"values": ["PT3H"]
}
}
]
}
}
}

Availability Response (with ?duration=PT3H):

{
"timeSlots": [
{
"start": "2024-03-15T18:00:00Z",
"end": "2024-03-15T21:00:00Z",
"score": 1
},
{
"start": "2024-03-15T21:00:00Z",
"end": "2024-03-16T00:00:00Z",
"score": 1
},
{
"start": "2024-03-16T09:00:00Z",
"end": "2024-03-16T12:00:00Z",
"score": 1
}
],
"durationOptions": {
"type": "discrete",
"values": ["PT3H"]
},
"selectedDuration": "PT3H"
}

Example 4: One-Off Specific Dates​

Scenario: Special availability on specific dates only, 10am-2pm

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT2H"]
},
"windows": [
{
"type": "oneOff",
"start": {
"dateTime": "2024-12-25T10:00:00Z"
},
"end": {
"dateTime": "2024-12-25T14:00:00Z"
}
},
{
"type": "oneOff",
"start": {
"dateTime": "2024-12-26T10:00:00Z"
},
"end": {
"dateTime": "2024-12-26T14:00:00Z"
}
}
]
}
}
}

Availability Response:

{
"timeSlots": [
{
"start": "2024-12-25T10:00:00Z",
"end": "2024-12-25T12:00:00Z",
"score": 1
},
{
"start": "2024-12-25T12:00:00Z",
"end": "2024-12-25T14:00:00Z",
"score": 1
},
{
"start": "2024-12-26T10:00:00Z",
"end": "2024-12-26T12:00:00Z",
"score": 1
}
],
"durationOptions": {
"type": "discrete",
"values": ["PT2H"]
}
}

Example 5: Mixed Schedule with Per-Window Durations​

Scenario:

  • Regular: Mon-Fri 10am-6pm, 30min to 2h in 30min increments
  • Special Dec 15: 12pm-2pm, exactly 2h (fit to window)
  • Special Dec 16: 3pm-6pm, exactly 3h
{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "range",
"min": "PT30M",
"max": "PT2H",
"step": "PT30M"
},
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Madrid",
"startTime": "10:00",
"duration": "PT8H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": [
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY"
]
}
},
{
"type": "oneOff",
"start": {
"dateTime": "2024-12-15T12:00:00+01:00",
"timeZone": "Europe/Madrid"
},
"end": {
"dateTime": "2024-12-15T14:00:00+01:00",
"timeZone": "Europe/Madrid"
},
"durations": {
"type": "fit"
}
},
{
"type": "oneOff",
"start": {
"dateTime": "2024-12-16T15:00:00+01:00",
"timeZone": "Europe/Madrid"
},
"end": {
"dateTime": "2024-12-16T18:00:00+01:00",
"timeZone": "Europe/Madrid"
},
"durations": {
"type": "discrete",
"values": ["PT3H"]
}
}
],
"exceptions": ["2024-12-25", "2024-12-26"]
}
}
}

Availability Response (default, no duration filter):

{
"timeSlots": [
{
"start": "2024-12-15T10:00:00+01:00",
"end": "2024-12-15T10:30:00+01:00",
"score": 1
},
{
"start": "2024-12-15T10:00:00+01:00",
"end": "2024-12-15T11:00:00+01:00",
"score": 1
},
{
"start": "2024-12-15T12:00:00+01:00",
"end": "2024-12-15T14:00:00+01:00",
"score": 1
}
],
"durationOptions": {
"type": "range",
"min": "PT30M",
"max": "PT2H",
"step": "PT30M"
}
}

Availability Response (with ?duration=PT3H):

{
"timeSlots": [
{
"start": "2024-12-16T15:00:00+01:00",
"end": "2024-12-16T18:00:00+01:00",
"score": 1
}
],
"durationOptions": {
"type": "range",
"min": "PT30M",
"max": "PT2H",
"step": "PT30M"
},
"selectedDuration": "PT3H"
}

Example 6: Complex Recurrence (Monthly Pattern)​

Scenario: Available on 1st and 15th of every month, 2pm-5pm

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT1H", "PT2H"]
},
"windows": [
{
"type": "recurring",
"timeZone": "America/Los_Angeles",
"startTime": "14:00",
"duration": "PT3H",
"recurrence": {
"frequency": "MONTHLY",
"daysOfMonth": [1, 15]
}
}
]
}
}
}

Availability Response:

{
"timeSlots": [
{
"start": "2024-02-01T14:00:00-08:00",
"end": "2024-02-01T15:00:00-08:00",
"score": 1
},
{
"start": "2024-02-01T14:00:00-08:00",
"end": "2024-02-01T16:00:00-08:00",
"score": 1
},
{
"start": "2024-02-15T14:00:00-08:00",
"end": "2024-02-15T15:00:00-08:00",
"score": 1
}
],
"durationOptions": {
"type": "discrete",
"values": ["PT1H", "PT2H"]
}
}

Example 7: Flexible Duration Range​

Scenario: Allow any duration from 1h to 4h in 15min increments

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "range",
"min": "PT1H",
"max": "PT4H",
"step": "PT15M"
},
"windows": [
{
"type": "recurring",
"timeZone": "Europe/Berlin",
"startTime": "09:00",
"duration": "PT9H",
"recurrence": {
"frequency": "DAILY"
}
}
]
}
}
}

Availability Response (with ?duration=PT2H30M):

{
"timeSlots": [
{
"start": "2024-01-15T09:00:00+01:00",
"end": "2024-01-15T11:30:00+01:00",
"score": 1
},
{
"start": "2024-01-15T09:15:00+01:00",
"end": "2024-01-15T11:45:00+01:00",
"score": 1
}
],
"durationOptions": {
"type": "range",
"min": "PT1H",
"max": "PT4H",
"step": "PT15M"
},
"selectedDuration": "PT2H30M"
}

Example 8: Daily Recurrence with Interval​

Scenario: Available every other day, 10am-4pm

{
"availabilitySchedule": {
"schedule": {
"defaultDurations": {
"type": "discrete",
"values": ["PT1H", "PT2H"]
},
"windows": [
{
"type": "recurring",
"timeZone": "UTC",
"startTime": "10:00",
"duration": "PT6H",
"recurrence": {
"frequency": "DAILY",
"interval": 2
}
}
]
}
}
}

This creates availability on alternating days (e.g., Jan 1, Jan 3, Jan 5, ...).

Querying Availability​

When querying the availability endpoint, you can filter by duration:

GET /v1/event-types/{id}/availability?from=2024-01-15&days=7&duration=PT1H

Query Parameters:

  • from: Start date (YYYY-MM-DD)
  • days: Number of days to search (default: 7)
  • duration: (Optional) Filter slots by this specific duration. Must match one of the available durationOptions.

Response includes:

  • timeSlots: Array of available time slots
  • durationOptions: Available duration options for this event type (null for legacy schedules)
  • selectedDuration: The duration that was used to filter slots (only present when duration query param was provided)

Slot Step​

The slotStep field controls how frequently slots are generated within a window. If not specified, it defaults to the smallest available duration.

Example: With a window from 9am-5pm and slotStep: "PT30M", slots will be generated every 30 minutes:

  • 09:00, 09:30, 10:00, 10:30, ...

If slotStep is not provided and you have discrete durations ["PT30M", "PT1H"], it will default to PT30M (the smallest).

Exception Dates​

You can exclude specific dates from recurring windows:

{
"schedule": {
"windows": [
{
"type": "recurring",
"timeZone": "America/New_York",
"startTime": "09:00",
"duration": "PT8H",
"recurrence": {
"frequency": "WEEKLY",
"daysOfWeek": ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]
}
}
],
"exceptions": ["2024-12-25", "2024-12-26", "2025-01-01"]
}
}

Exception dates are interpreted in the timezone of each window. For multi-timezone schedules, an exception date will exclude that date in all timezones.

Migration from Legacy System​

The legacy repeatingAvailability system continues to work for backward compatibility. However, we recommend migrating to availabilitySchedule for all new implementations. The new availabilitySchedule system takes precedence when both are present.

Key Differences:

FeatureLegacy (repeatingAvailability)New (availabilitySchedule)
Cross-midnight❌ Not supported✅ Supported
Multi-day events❌ Not supported✅ Supported
One-off dates❌ Not supported✅ Supported
Complex recurrence❌ Weekly only✅ Daily, Weekly, Monthly, Yearly
Multiple durations❌ Single fixed duration✅ Discrete, Range, or Fit
Per-window durations❌ Not supported✅ Supported
Exception dates❌ Not supported✅ Supported

API Reference​

Field Structure:

interface AvailabilitySchedule {
schedule?: ScheduleDefinition;
ical?: string; // Raw iCal format (alternative to schedule)
}

interface ScheduleDefinition {
defaultDurations?: DurationOptions;
slotStep?: string; // ISO 8601 duration
windows: AvailabilityWindow[];
exceptions?: string[]; // Dates in YYYY-MM-DD format
}

type AvailabilityWindow = RecurringWindow | OneOffWindow;

interface RecurringWindow {
type: "recurring";
timeZone: string; // IANA timezone (e.g., "America/New_York")
startTime: string; // HH:MM format
duration: string; // ISO 8601 duration (supports cross-midnight)
recurrence: Recurrence;
durations?: DurationOptions; // Optional per-window override
}

interface OneOffWindow {
type: "oneOff";
start: ZonedDateTime;
end: ZonedDateTime;
durations?: DurationOptions; // Optional per-window override
}

interface ZonedDateTime {
dateTime: string; // ISO 8601 with offset (e.g., "2024-03-15T18:00:00+01:00")
timeZone?: string; // Optional IANA timezone
}

interface Recurrence {
frequency: "DAILY" | "WEEKLY" | "MONTHLY" | "YEARLY";
interval?: number; // Every N periods (default: 1)
daysOfWeek?: DayOfWeek[]; // For WEEKLY
daysOfMonth?: number[]; // For MONTHLY (1-31)
monthsOfYear?: number[]; // For YEARLY (1-12)
until?: string; // End date (YYYY-MM-DD)
count?: number; // Max occurrences
}

type DurationOptions =
| { type: "discrete"; values: string[] } // ISO 8601 durations
| { type: "range"; min: string; max?: string; step: string }
| { type: "fit" };

type DayOfWeek =
| "MONDAY"
| "TUESDAY"
| "WEDNESDAY"
| "THURSDAY"
| "FRIDAY"
| "SATURDAY"
| "SUNDAY";

Validation Rules:

  1. Either defaultDurations must be provided, OR every window must have its own durations field
  2. For range durations, if max is not provided, it will be derived from the window size
  3. fit durations can only be used with windows that have a fixed size
  4. Discrete duration values must not exceed the window duration
  5. daysOfWeek should only be used with WEEKLY frequency
  6. daysOfMonth should only be used with MONTHLY or YEARLY frequency
  7. monthsOfYear should only be used with YEARLY frequency