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_blockerflag set totrue. 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.yamlfor all/api/v1/availability/*endpoints in this guidepaths/public/availability.yamlforGET /api/v1/service-configurationpaths/public/availability.yamlforGET /api/v1/intervals/waitlist-startandGET /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 |