Availability API
The Availability API allows you to query available time slots for products and retrieve add-ons associated with products.
Query Available Slots
Retrieve available time slots for a specific product within a date range.
GET /api/v1/availability
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
product_id | string | Yes | Product identifier |
site_id | string | Yes | Site identifier |
date_from | string | Yes | Start date (YYYY-MM-DD format) |
date_to | string | No | End date (YYYY-MM-DD format). Defaults to date_from if not provided |
party_size | number | No | Number of participants (default: 1) |
include_labels | boolean | No | Include slot label codes in response (default: true) |
Example Request
GET /api/v1/availability?product_id=p_demo&site_id=s_demo&date_from=2025-10-10&date_to=2025-10-17&party_size=4&include_labels=true
x-tenant-id: t_demo
Response
Status: 200 OK
{
"request_id": "req_abc123",
"productId": "p_demo",
"siteId": "s_demo",
"dateFrom": "2025-10-10",
"dateTo": "2025-10-17",
"partySize": 4,
"slots": [
{
"slotId": "slot_123",
"startsAt": "2025-10-10T10:00:00.000Z",
"endsAt": "2025-10-10T11:00:00.000Z",
"availableCapacity": 12,
"totalCapacity": 16,
"labelCodes": ["adults_only"],
"pricingPreview": {
"subtotal": 80.0,
"taxTotal": 20.0,
"grandTotal": 100.0,
"currency": "EUR"
}
},
{
"slotId": "slot_124",
"startsAt": "2025-10-10T11:30:00.000Z",
"endsAt": "2025-10-10T12:30:00.000Z",
"availableCapacity": 8,
"totalCapacity": 16,
"labelCodes": [],
"pricingPreview": {
"subtotal": 80.0,
"taxTotal": 20.0,
"grandTotal": 100.0,
"currency": "EUR"
}
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
request_id | string | Unique request identifier |
productId | string | Product identifier from request |
siteId | string | Site identifier from request |
dateFrom | string | Start date from request |
dateTo | string | End date from request |
partySize | number | Party size from request |
slots | array | Array of available slots |
slots[].slotId | string | Unique slot identifier |
slots[].startsAt | string | Slot start time (ISO 8601) |
slots[].endsAt | string | Slot end time (ISO 8601) |
slots[].availableCapacity | number | Available capacity (total - booked) |
slots[].totalCapacity | number | Total capacity for this slot |
slots[].labelCodes | string[] | Array of label codes (e.g., "adults_only", "toddler_friendly") |
slots[].pricingPreview | object | Estimated pricing for party size |
slots[].pricingPreview.subtotal | number | Subtotal before tax |
slots[].pricingPreview.taxTotal | number | Tax amount |
slots[].pricingPreview.grandTotal | number | Total price including tax |
slots[].pricingPreview.currency | string | Currency code (e.g., "EUR") |
Empty Response
If no slots are available, the response will still be 200 OK with an empty slots array:
{
"request_id": "req_abc123",
"productId": "p_demo",
"siteId": "s_demo",
"dateFrom": "2025-10-10",
"dateTo": "2025-10-17",
"partySize": 4,
"slots": []
}
Error Responses
400 Bad Request - Invalid parameters
{
"error": "VALIDATION_ERROR",
"message": "Missing required parameter: product_id",
"code": 400
}
404 Not Found - Product or site not found
{
"error": "NOT_FOUND",
"message": "Product or site not found",
"code": 404
}
Get Product Add-ons
Retrieve available add-ons for a specific product.
GET /api/v1/availability/products/:productId/addons
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
productId | string | Yes | Product identifier |
Example Request
GET /api/v1/availability/products/p_demo/addons
x-tenant-id: t_demo
Response
Status: 200 OK
{
"product_id": "p_demo",
"addons": [
{
"id": "addon_123",
"name": "Party Room",
"description": "Private party room for 2 hours",
"addonType": "resource",
"mode": "yesno",
"priceType": "fixed",
"price": 50.0,
"currency": "EUR",
"available": true
},
{
"id": "addon_124",
"name": "Equipment Upgrade",
"description": "Premium equipment set",
"addonType": "upgrade",
"mode": "per_participant",
"priceType": "per_person",
"unitPrice": 10.0,
"currency": "EUR",
"available": true
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
product_id | string | Product identifier |
addons | array | Array of available add-ons |
addons[].id | string | Add-on identifier |
addons[].name | string | Add-on name |
addons[].description | string | Add-on description |
addons[].addonType | string | Add-on type: item, service, upgrade, or resource |
addons[].mode | string | Selection mode: yesno (checkbox), free_qty (customer enters quantity), or per_participant (matches party size) |
addons[].priceType | string | Price calculation: fixed, per_person, or percentage |
addons[].price | number | Fixed price (present when priceType is fixed and mode is yesno) |
addons[].unitPrice | number | Price per unit (present when mode is free_qty or per_participant) |
addons[].currency | string | Currency code |
addons[].available | boolean | Whether add-on is currently available |
Mode and pricing details: See the Add-ons section in the Catalog Guide for full descriptions of types, modes, and price types.
Usage Examples
cURL
# Query available slots
curl -X GET "http://localhost:3001/api/v1/availability?product_id=p_demo&site_id=s_demo&date_from=2025-10-10&date_to=2025-10-17&party_size=4&include_labels=true" \
-H "x-tenant-id: t_demo"
# Get product add-ons
curl -X GET "http://localhost:3001/api/v1/availability/products/p_demo/addons" \
-H "x-tenant-id: t_demo"
JavaScript/TypeScript
interface AvailabilityQuery {
productId: string;
siteId: string;
dateFrom: string;
dateTo?: string;
partySize?: number;
includeLabels?: boolean;
}
interface Slot {
slotId: string;
startsAt: string;
endsAt: string;
availableCapacity: number;
totalCapacity: number;
labelCodes: string[];
pricingPreview?: {
subtotal: number;
taxTotal: number;
grandTotal: number;
currency: string;
};
}
async function queryAvailability(
tenantId: string,
query: AvailabilityQuery,
): Promise<Slot[]> {
const params = new URLSearchParams({
product_id: query.productId,
site_id: query.siteId,
date_from: query.dateFrom,
party_size: (query.partySize || 1).toString(),
include_labels: (query.includeLabels !== false).toString(),
});
if (query.dateTo) {
params.append('date_to', query.dateTo);
}
const response = await fetch(
`http://localhost:3001/api/v1/availability?${params}`,
{
headers: {
'x-tenant-id': tenantId,
},
},
);
if (!response.ok) {
throw new Error('Failed to query availability');
}
const data = await response.json();
return data.slots || [];
}
// Usage
const slots = await queryAvailability('t_demo', {
productId: 'p_demo',
siteId: 's_demo',
dateFrom: '2025-10-10',
dateTo: '2025-10-17',
partySize: 4,
includeLabels: true,
});
console.log(`Found ${slots.length} available slots`);
Python
import requests
from typing import Optional, List, Dict
def query_availability(
tenant_id: str,
product_id: str,
site_id: str,
date_from: str,
date_to: Optional[str] = None,
party_size: int = 1,
include_labels: bool = True,
) -> List[Dict]:
params = {
'product_id': product_id,
'site_id': site_id,
'date_from': date_from,
'party_size': party_size,
'include_labels': include_labels,
}
if date_to:
params['date_to'] = date_to
response = requests.get(
'http://localhost:3001/api/v1/availability',
params=params,
headers={'x-tenant-id': tenant_id},
)
response.raise_for_status()
data = response.json()
return data.get('slots', [])
# Usage
slots = query_availability(
tenant_id='t_demo',
product_id='p_demo',
site_id='s_demo',
date_from='2025-10-10',
date_to='2025-10-17',
party_size=4,
include_labels=True,
)
print(f'Found {len(slots)} available slots')
Slot Labels
Slots can have labels that indicate special conditions or requirements:
adults_only: Slot is restricted to adults onlytoddler_friendly: Slot is suitable for toddlersbeginner_friendly: Suitable for beginnersadvanced: For advanced participants only
Labels are included in the labelCodes array when include_labels=true. Always check labels to ensure they match your requirements before creating a booking.
Pricing Preview
The pricingPreview field provides an estimated price for the specified party size. This is a preliminary calculation and may change when you create a booking hold, as:
- Exact pricing rules are applied
- Promotions may be available
- Tax rates may vary
Always use the pricing hash returned when creating a booking hold to ensure price consistency.