Skip to main content

Overview

Before creating a booking, your integration must walk through a sequence of availability checks. Each step validates that the requested combination of date, shift, experience, and add-ons is available for the given party size. The diagram below shows the complete flow at a high level.

The availability object

Throughout this flow, many objects in the response carry their own availability object. Whenever an object includes an availability, it manages its own availability independently — this applies at every level, from the top-level request down to individual entities such as work days, shifts, time slots, experiences, add-on groups, individual add-ons, and floor plan areas, among others. This means a parent being available does not imply its children are: a shift can be available while a specific experience or add-on within it is not. Always check the availability of every object before offering it to the customer, not just the top-level one. Each availability object exposes:
  • isAvailable — whether that specific object is available. Always check this first.
  • When isAvailable is falseoutcome, code, and detail explain why, and fallbackOptions lists alternative actions to offer the customer (see Handle fallbackOptions).

Identifying a shift and a time slot

Several endpoints in this flow carry {date} and {time} in the path. Both values come from the response that offered you the option — copy them, do not compute them. Shifts have no public identifier on purpose: the IDs behind a work day’s shifts can change at any time, so a stored one would go stale without warning. The booking window is the stable handle instead — any time between firstBookingAt and lastBookingAt resolves to that shift, and the response covers the whole shift. Calling once per candidate time returns the same thing every time.
{date} is the calendar date of {time}, not the work day. The two differ when a shift crosses midnight: a shift running from 2025-03-20T20:00:00+02:00 to 2025-03-21T01:00:00+02:00 belongs to the work day starting on 2025-03-20, but its 00:30 slot is requested with {date} set to 2025-03-21. Taking both values from the same ISO datetime gets this right without having to think about it.
Send {time} as the local time inside that ISO value, with no offset — see Time Zones.

Handle fallbackOptions

When availability.isAvailable is false, the response includes a fallbackOptions array with one or more actions to offer the user. Always check this array before showing a generic error. code sits beside them and says exactly which rule the request hit. Read it when you want to tell the customer what to change rather than offer a generic alternative — see AvailabilityCode.

Step 1 — Get Calendar Availability (optional)

Use this endpoint to retrieve availability across a date range. This is typically used to populate a calendar view before the user picks a specific date. It is not required — you can go directly to Get Work Day Availability if you already have a date. Endpoint: POST /availability/calendar

Step 2 — Get Work Day Availability

Retrieves availability for a specific date and returns the list of available shifts for the given party size. Endpoint: POST /availability/work-days/{date}
Always send status: CONFIRMED on all availability requests. If no availability is found, fallbackOptions may offer alternative actions — such as requesting the booking or joining the wait list — depending on the venue configuration.
The response includes a shifts[] array. Each shift exposes two flags that determine the next steps:

Step 3 — Experiences

If shift.hasExperiences is true, you must check experience availability before proceeding to Get Shift Availability. Retrieves the experiences available for the selected shift. The response includes shift.isExperienceRequired, which determines whether the user must select an experience to continue or may proceed without one. Endpoint: POST /availability/work-days/{date}/shifts/{time}/experiences

Ticket quantity

tickets is always required. automaticTicketQuantity decides who picks the value. When it is false, the customer picks. Offer this range:
maxTicketsAvailable still counts tickets that are already sold. Offer it as the maximum and the customer picks a number the venue cannot honour, which Get Shift Availability rejects on the very next call with SHIFT_AVAILABLE_TICKETS_EXCEEDED.
When it is true, compute the value instead of asking the customer:
where bookingSize is the booking size.
The match must be exact. A different value makes the experience unavailable with EXPERIENCE_AUTO_TICKETS_AND_BOOKING_SIZE_NOT_MATCH, and if it reaches Create Booking, HTTP 409 BOOKING_AVAILABILITY_NOT_FOUND — which says nothing about tickets.
Booking size is checked separately against minBookingSize and maxBookingSize; it does not constrain the ticket count.

Step 4 — Experience Add-ons

If the selected experience has add-ons, call this endpoint to retrieve the available add-ons. Endpoint: POST /availability/work-days/{date}/shifts/{time}/experiences/add-ons Add-on availability is checked at three levels — the request (availability), the group (addOnGroup.availability), and each individual add-on (addOnGroup.addOns[].availability). Offer only the add-ons whose isAvailable is true, and if the group itself is unavailable, continue without add-ons. Once the group is available, use addOnGroup.minTotalQuantity to determine whether selecting an add-on is mandatory (> 0) or optional (= 0).

Step 5 — Get Shift Availability

Retrieves the available time slots within the selected shift. Endpoint: POST /availability/work-days/{date}/shifts/{time}/time-slots

How timeSlots[] is shaped

One entry per bookable combination of start time and floor plan area. startAt is not unique — the same time comes back once per area, each entry with its own availability — and the entries are not in chronological order. Do not deduplicate by time: you would keep one area’s availability at random, hiding times that were free and offering times that were full. floorPlanAreas[] can be wider than what is bookable. An area appears there even when it has no times of its own, so offer only the ones that also appear in timeSlots[].

Carry the floor plan area forward

Every entry in timeSlots[] brings its own floorPlanAreaId. Send it on each later call — add-ons, the final availability check and Create Booking. A null means there is no area to send.
When the shift offers areas open to online booking, leaving floorPlanAreaId out is not a validation error: the shift comes back unavailable, with SHIFT_BOOKING_FLOOR_PLAN_AREA_MUST_BE_DEFINED. The time was free — only the area was missing.

Step 6 — Time Slot Add-ons

If shift.hasAddOns is true, you must check time slot add-on availability after the user selects a time slot. Add-on availability is checked at three levels — the request (availability), the group (addOnGroup.availability), and each individual add-on (addOnGroup.addOns[].availability). Offer only the add-ons whose isAvailable is true, and if the group itself is unavailable, continue without add-ons. Once the group is available, use addOnGroup.minTotalQuantity to determine whether selecting an add-on is mandatory (> 0) or optional (= 0). Endpoint: POST /availability/work-days/{date}/time-slots/{time}/add-ons

Step 7 — Get Booking Availability

The final availability check before creating a booking. This endpoint validates the complete booking request and returns the applicable booking conditions, such as the cancellation policy, that must be presented to the user before proceeding. Endpoint: POST /availability/bookings/{date}/{time}
This step is mandatory. The response includes final booking conditions such as the cancellation policy that must be presented to the user before creating the booking.

Add-on names and prices

The top-level addOns resolves everything you requested — the shift’s add-ons and the experience’s, flattened — with their current name, price and currency, in the language of the request. Build the booking summary from it rather than from values cached earlier in the funnel, which can carry a price the venue has since changed, or the language the customer had selected then.