Availability & Booking Search

Find available time slots for services and resources. This guide covers the typical search flow and advanced scenarios like recurring bookings, series, and waitlists.

For general request conventions, see JSON-API Conventions. For authentication, see Authentication.


Prerequisites

  • An organization with at least one resource and one service configured
  • Public API endpoints — no authentication required (availability is public by default)
  • Organization context is derived from the resource/service being queried

Domain Model

Organization
  ├── Resources (rooms, desks, people, etc.)
  │     └── Schedule Groups → Schedules (weekly recurring) + Timeslots (fixed date-time blocks)
  └── Services (what can be booked — duration, pricing, capacity)
        └── Optional: own Schedules/Timeslots to constrain time further

Resources and Services exist at the same level under an Organization with a many-to-many relationship. A service can be offered on multiple resources, and a resource can have multiple services.

  • A resource is the bookable entity (e.g. a meeting room, a therapist). It has schedule groups containing schedules (weekly recurring availability) and/or timeslots (fixed date-time blocks).
  • A service defines booking rules: duration constraints, pricing, capacity. Services may optionally have their own schedules/timeslots — when present, a slot is bookable only when the resource's and service's availability periods overlap.
  • A booking always belongs to both a resource and a service.
  • A blocker is a booking without a service, with is_blocker flag set to true. It blocks availability on a resource without representing a real booking.

How Availability is Calculated

The availability engine merges a resource's schedules and timeslots into availability periods (= opening hours). These are then combined with the service's duration settings to generate bookable intervals. Existing bookings and blockers reduce the remaining capacity.


Typical Search Flow

Request path documentation:

  • paths/public/availability.yaml for all /api/v1/availability/* endpoints in this guide
  • paths/public/availability.yaml for GET /api/v1/service-configuration
  • paths/public/availability.yaml for GET /api/v1/intervals/waitlist-start and GET /api/v1/intervals/waitlist-end

The standard booking search follows these steps:

Step 1 — Get Service Configuration

Retrieve booking rules and the next available date for a service:

GET /api/v1/service-configuration?service_id={service_uuid}&resource_id={resource_uuid}

Response includes:

Field Description
mainService Service identity and pricing
unit Duration unit (minutes, hours, days)
minDuration / maxDuration Allowed booking duration range
price Pricing rules and modifiers
meta.next_available_date First date with availability

Use next_available_date to initialize the calendar view.

Step 2 — Find Available Dates

Get a list of dates with available slots within a range:

GET /api/v1/availability/start-dates?service_id={service_uuid}&start_date=2026-04-01&end_date=2026-04-30

Optional parameters:

Parameter Description
resource_id Limit to a specific resource
original_booking_id Exclude an existing booking's time (for rebooking)

Response: An array of date strings that have at least one available slot.

Step 3 — Get Start Time Intervals

Once the user selects a date, fetch available start times:

GET /api/v1/availability/start?service_id={service_uuid}&date=2026-04-15

Optional parameters:

Parameter Type Description
resource_id string Limit to a specific resource
duration integer Desired duration in minutes (narrows results)

Response: An array of interval objects:

[
  {
    "start_date": "2026-04-15T09:00:00+02:00",
    "available": true,
    "number_available": 3,
    "remaining_number_available": 2,
    "resource_ids": ["r1", "r2", "r3"]
  },
  {
    "start_date": "2026-04-15T10:00:00+02:00",
    "available": false,
    "unavailability_type": "booked_out"
  }
]

Unavailability Types

Type Meaning
none Available
booked_out All capacity taken
lead_time_conflict Too close to current time
under_min_duration Remaining time is below minimum
staggered_conflict Conflicts with staggered booking rules

Step 4 — Get End Time Intervals (Flexible Duration Only)

If the service allows flexible (variable) duration, fetch valid end times after the user picks a start. This lets the user request multiple possible end intervals for the chosen start interval.

GET /api/v1/availability/end?service_id={service_uuid}&date_time=2026-04-15T09:00:00%2B02:00

Optional parameters:

Parameter Type Description
resource_id string Limit to a specific resource
adhoc boolean Whether this is an ad-hoc booking

Response: Array of end intervals with availability status.

Note: Skip this step for services with fixed or auto duration — the end time is calculated automatically from start_date + duration.


Additional Endpoints

Next Available Date

Get the absolute next available date without scanning a range:

GET /api/v1/availability/next-date?service_id={service_uuid}

Useful for "book next available" shortcuts.

Availability Periods (Opening Hours)

Get raw availability blocks (opening hours) for a resource:

GET /api/v1/availability/periods?service_id={service_uuid}&resource_id={resource_uuid}

These represent the merged schedule/timeslot periods — the times when the resource is generally open. Useful for calendar heatmaps or dense schedule displays.

Upcoming Intervals

Get the next N available intervals from now. This endpoint allows a list-based selection flow without requiring the user to pick a day in a calendar first:

GET /api/v1/availability/upcoming-intervals?service_id={service_uuid}
Parameter Type Description
start_date string Start scanning from this date
duration integer Desired duration in minutes
include_unavailable boolean Include unavailable slots in results

Advanced Scenarios

Recurring Bookings

For bookings that repeat on a schedule:

GET /api/v1/availability/recurring?service_id={service_uuid}&resource_id={resource_uuid}

Returns availability data structured for recurring selection (e.g. "every Monday 10:00–11:00").

Series / Timeslot-Based Bookings

Some services use predefined timeslot series (e.g. a course with 10 sessions):

GET /api/v1/availability/series?timeslot_series_id={series_uuid}&service_id={service_uuid}

Get individual intervals within a series:

GET /api/v1/availability/series-intervals?timeslot_series_id={series_uuid}

Waitlist

When a slot is fully booked, the waitlist endpoints provide intervals where customers can register interest:

GET /api/v1/intervals/waitlist-start?service_id={service_uuid}&date=2026-04-15
GET /api/v1/intervals/waitlist-end?service_id={service_uuid}&date_time=2026-04-15T09:00:00%2B02:00

These follow the same pattern as start/end intervals but return waitlist-eligible slots.

For the concrete UI rule set, auth requirements, and the POST /api/v1/waitlist-spots payload, see Waitlist.


Timezone Handling

All dates in requests should include timezone offsets (ISO 8601 / Atom format):

2026-04-15T09:00:00+02:00

Pass the timezone parameter when the user's timezone differs from the resource's configured timezone:

GET /api/v1/availability/start?service_id={id}&date=2026-04-15&timezone=America/New_York

The API returns dates in the resource's timezone by default. Interval objects include both UTC (start_date) and local (local_date_time) representations when timezone conversion applies.


Common Errors

Error Cause Solution
422 — service_id required Missing service_id parameter Always include service_id in availability requests
422 — invalid date format Date not in Y-m-d or Atom format Use YYYY-MM-DD for date-only params, Atom for datetime
Empty results Resource has no schedule or service is inactive Verify the resource has an active schedule and the service is published