Activities, Calendar & Timeslots
Browse activities, check availability calendars, retrieve time slots, and discover eligible add-ons using the ResytechApi client.
This page covers the read-side of the booking flow: fetching activity details, checking calendar availability, loading time slots for a given date, and discovering eligible add-ons.
All examples assume you have already initialized the API client:
const api = new ResytechApi({ debug: true });
const init = await api.initialization.initialize({ identifier: 'session-1' });Activities
getActivity
Retrieve full details for a single activity, including equipment, durations, media, custom fields, agreements, and trip protection settings.
const result = await api.activity.getActivity('activity-uuid');
if (result.success) {
const activity = result.activity;
console.log(activity.name, '- Base price:', activity.basePrice);
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
uuid | string | Yes | Activity unique identifier |
ActivityResponse
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
activity | Activity | Full activity details (see below) |
Activity Type
| Field | Type | Description |
|---|---|---|
uuid | string | Unique identifier |
name | string | Display name |
basePrice | number | Base price in cents |
description | string | Full description |
cancellationPolicy | string | Cancellation policy text |
details | string | Additional details |
media | Media[] | Images and videos |
durations | Duration[] | Available booking durations |
equipment | Equipment[] | Available equipment (boats, kayaks, etc.) |
manifest | Manifest | Guest limits, age restrictions, demographics |
firstAvailableDate | Date | Earliest bookable date |
allowEquipmentMixing | boolean | Whether customers can book multiple equipment types |
maxEquipmentPerBooking | number | Max equipment items per booking |
customFields | CustomField[] | Custom form fields for checkout |
agreements | ActivityAgreement[] | Agreements the customer must accept |
type | number | Activity type identifier |
allowPrivateTours | boolean | Whether private tours are available |
dynamicDurationSettings | ActivityDynamicDurationSetting | Dynamic duration config |
scheduling | ActivityScheduling | Date range and cutoff settings |
tripProtection | TripProtection | Trip protection configuration |
Supporting Types
Duration
| Field | Type | Description |
|---|---|---|
uuid | string | Duration identifier (pass to cart/calendar requests) |
minutes | number | Duration length in minutes |
Equipment
| Field | Type | Description |
|---|---|---|
uuid | string | Equipment identifier |
name | string | Display name |
description | string | Short description |
details | string | Detailed info |
quantity | number | Total inventory |
capacity | number | Seats per unit |
media | Media[] | Images |
addons | Addon[] | Equipment-specific add-ons |
amenities | Amenity[] | Equipment amenities |
properties | EquipmentProperty[] | Custom properties (e.g., length, weight) |
Manifest
| Field | Type | Description |
|---|---|---|
guestLimit | number | Maximum guests per booking |
ageRestriction | number | Minimum age |
guestMinimum | number | Minimum guests per booking |
demographics | Demographic[] | Guest demographics (adults, children, etc.) |
Media
| Field | Type | Description |
|---|---|---|
uuid | string | Media identifier |
order | number | Display order |
type | number | Media type (image, video, etc.) |
uri | string | Full-size URL |
thumbnailUri | string | Thumbnail URL |
Calendar
Calendar endpoints return monthly availability data. Use them to build date pickers that show which days have open slots.
getActivityCalendar
Get availability for a specific activity in a given month.
const calendar = await api.calendar.getActivityCalendar({
activity: 'activity-uuid',
month: 7,
year: 2025,
includePrices: true
});
if (calendar.success) {
calendar.calendar.days.forEach(day => {
console.log(day.date, day.isAvailable ? `$${day.price}` : 'unavailable');
});
}getCartCalendar
Same as getActivityCalendar, but returns availability that accounts for items already in the cart. Use this when the customer is adding a second activity to an existing booking.
const calendar = await api.calendar.getCartCalendar({
activity: 'activity-uuid',
month: 7,
year: 2025,
cartId: 'existing-cart-id'
});ActivityCalendarRequest
| Field | Type | Required | Description |
|---|---|---|---|
activity | string | Yes | Activity UUID |
month | number | Yes | Month (1-12) |
year | number | Yes | Year (e.g. 2025) |
includePrices | boolean | No | Include per-day pricing |
duration | string | No | Duration UUID to filter by |
startTime | string | No | Filter by start time |
equipment | ClientShoppingCartEquipment[] | No | Equipment selection to check against |
durationMins | number | No | Duration in minutes (for dynamic durations) |
cartId | string | No | Cart ID (used by getCartCalendar) |
CalendarResponse
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
calendar | CalendarMonth | Month data with daily availability |
CalendarMonth
| Field | Type | Description |
|---|---|---|
month | number | Month number (1-12) |
year | number | Year |
days | ActivityCalendarDay[] | Array of day objects |
ActivityCalendarDay
| Field | Type | Description |
|---|---|---|
date | string | Date string (YYYY-MM-DD) |
isAvailable | boolean | Whether there is availability on this day |
price | number | Starting price for this day (if includePrices was true) |
isEstimatedPrice | boolean | Whether the price is an estimate |
blackoutMessage | string | Reason the day is blacked out (if applicable) |
Time Slots
Once the customer selects a date, load the available time slots for that day.
getActivityTimeSlots
Get time slots for a specific activity on a given date.
const slots = await api.timeslots.getActivityTimeSlots({
activity: 'activity-uuid',
date: '2025-07-15',
durationMins: 60
});
if (slots.success) {
slots.timeSlots.forEach(slot => {
console.log(`Price: $${slot.price}, Seats left: ${slot.remainingSeats}`);
});
}getLocationTimeSlots
Get time slots for all activities at the location. Useful for location-wide availability views.
const locationSlots = await api.timeslots.getLocationTimeSlots({
date: '2025-07-15',
durationMins: 60
});
if (locationSlots.success) {
locationSlots.results.forEach(activitySlots => {
console.log('Activity:', activitySlots.uuid);
console.log('Slots:', activitySlots.slots?.length);
console.log('Next available:', activitySlots.nextAvailableDate);
});
}getCartTimeSlots
Get time slots that account for items already in the active cart.
const cartSlots = await api.timeslots.getCartTimeSlots({
date: '2025-07-15',
durationMins: 60
});TimeSlotRequest
| Field | Type | Required | Description |
|---|---|---|---|
date | string | Yes | Date in YYYY-MM-DD format |
activity | string | No | Activity UUID (recommended for activity-specific queries) |
duration | string | No | Duration UUID |
durationMins | number | No | Duration in minutes (for dynamic durations) |
equipment | ClientShoppingCartEquipment[] | No | Equipment selection to check availability against |
isPrivateTour | boolean | No | Filter for private tour availability |
ignoreEarlyCutoff | boolean | No | Ignore early booking cutoff rules |
ActivityTimeSlotsResponse
Returned by getActivityTimeSlots and getCartTimeSlots.
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
timeSlots | ActivityTimeSlot[] | Available time slots |
LocationTimeSlotsResponse
Returned by getLocationTimeSlots.
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
results | LocationAllActivityTimeSlots[] | Slots grouped by activity |
ActivityTimeSlot
| Field | Type | Description |
|---|---|---|
price | number | Price for this time slot |
remainingSeats | number | Number of seats still available |
canBookPrivateTour | boolean | Whether a private tour can be booked at this time |
LocationAllActivityTimeSlots
| Field | Type | Description |
|---|---|---|
uuid | string | Activity UUID |
slots | ActivityTimeSlot[] | Available slots for this activity |
nextAvailableDate | string | Next date with availability (if no slots on requested date) |
Add-ons
getEligibleAddons
Retrieve add-ons that are available for a given activity, date, and time combination.
const addons = await api.addon.getEligibleAddons({
activity: 'activity-uuid',
date: '2025-07-15',
time: '10:00'
});
if (addons.success) {
addons.addons.forEach(addon => {
console.log(`${addon.name} - $${addon.price} (${addon.quantity} available)`);
});
}GetEligibleAddonsRequest
| Field | Type | Required | Description |
|---|---|---|---|
activity | string | Yes | Activity UUID |
date | string | Yes | Date in YYYY-MM-DD format |
time | string | Yes | Time in HH:mm format |
duration | string | No | Duration UUID |
dynamicDurationMinutes | number | No | Duration in minutes (for dynamic durations) |
equipment | ClientShoppingCartEquipment[] | No | Equipment selection for context |
GetEligibleAddonsResponse
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
addons | EligibleAddon[] | List of eligible add-ons |
EligibleAddon
| Field | Type | Description |
|---|---|---|
uuid | string | Add-on identifier |
name | string | Display name |
description | string | Description |
price | number | Price per unit |
quantity | number | Available quantity |
mediaUri | string | Image URL |
Full Example: Browse to Book
This example walks through the complete read-side flow: list activities, check the calendar, get time slots, and discover add-ons.
const api = new ResytechApi({ debug: true });
// 1. Initialize and get available activities
const init = await api.initialization.initialize({
identifier: 'booking-session'
});
if (!init.success) {
console.error('Init failed:', init.message);
return;
}
const activities = init.activities;
console.log(`Found ${activities.length} activities`);
// 2. Get full details for the first activity
const activityUuid = activities[0].uuid;
const activityResult = await api.activity.getActivity(activityUuid);
const activity = activityResult.activity;
console.log(`${activity.name} - ${activity.durations.length} durations available`);
console.log(`Equipment: ${activity.equipment.map(e => e.name).join(', ')}`);
// 3. Check calendar for next month
const now = new Date();
const nextMonth = now.getMonth() + 2; // getMonth() is 0-indexed, API is 1-indexed
const year = nextMonth > 12 ? now.getFullYear() + 1 : now.getFullYear();
const month = nextMonth > 12 ? 1 : nextMonth;
const calendar = await api.calendar.getActivityCalendar({
activity: activityUuid,
month: month,
year: year,
includePrices: true,
duration: activity.durations[0]?.uuid
});
if (!calendar.success) {
console.error('Calendar failed:', calendar.message);
return;
}
// Find the first available date
const availableDay = calendar.calendar.days.find(d => d.isAvailable);
if (!availableDay) {
console.log('No availability this month');
return;
}
console.log(`First available: ${availableDay.date} at $${availableDay.price}`);
// 4. Get time slots for that date
const slots = await api.timeslots.getActivityTimeSlots({
activity: activityUuid,
date: availableDay.date,
duration: activity.durations[0]?.uuid
});
if (!slots.success || !slots.timeSlots?.length) {
console.log('No slots available');
return;
}
console.log(`${slots.timeSlots.length} time slots available`);
const firstSlot = slots.timeSlots[0];
console.log(`First slot: $${firstSlot.price}, ${firstSlot.remainingSeats} seats`);
// 5. Check for eligible add-ons
const addons = await api.addon.getEligibleAddons({
activity: activityUuid,
date: availableDay.date,
time: '10:00',
duration: activity.durations[0]?.uuid
});
if (addons.success && addons.addons?.length) {
console.log('Available add-ons:');
addons.addons.forEach(a => console.log(` ${a.name}: $${a.price}`));
}
// Ready to build a cart! See the Cart & Checkout guide.