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' });All response types on this page extend
ApiResponseBase, which addsmessage,statusCode,action, andisNetworkErroron top of the fields shown below. Always checksuccessbefore reading the payload.
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 dollars (decimal) |
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 |
priceType | number | 0 Per Booking, 1 Per Person, 2 Per Equipment, 3 Per Group |
includedGuests | number | Per Group only: guests covered by the duration (group) price. 0 otherwise. |
additionalGuestPrice | number | Per Group only: rate charged per guest above includedGuests. 0 otherwise. |
allowPrivateTours | boolean | Whether customers may book a departure exclusively |
privateToursOnly | boolean | Every booking is private: hide the private toggle and show a label; the server forces isPrivateTour on regardless of the request |
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 |
price | number | Base price for this duration |
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 |
Addon
| Field | Type | Description |
|---|---|---|
uuid | string | Add-on identifier |
name | string | Display name |
description | string | Description |
price | number | Price per unit |
Amenity
| Field | Type | Description |
|---|---|---|
id | string | Amenity identifier |
name | string | Display name |
description | string | Description |
iconType | number | Icon type indicator |
icon | string | Icon name or URI |
assignmentCount | number | Number of equipment items this amenity is assigned to |
EquipmentProperty
| Field | Type | Description |
|---|---|---|
id | string | Property identifier |
name | string | Property name (e.g., "Length") |
value | string | Property value (e.g., "12 ft") |
description | string | Optional description |
iconType | number | Icon type indicator |
icon | string | Icon name or URI |
featured | boolean | Whether to highlight this property |
Demographic
| Field | Type | Description |
|---|---|---|
uuid | string | Demographic identifier |
title | string | Display name (e.g., "Adult", "Child") |
description | string | Description |
CustomField
| Field | Type | Description |
|---|---|---|
uuid | string | Field identifier |
type | number | Field type code (see below) |
label | string | Field label shown to the customer |
required | boolean | Whether the customer must answer |
Field type codes and the answer format each expects in CustomFieldAnswer.answer:
| Code | Type | Answer format |
|---|---|---|
0 | Textarea | Free text |
1 | Text input | Free text |
2, 5 | Signature | PNG data URL (data:image/png;base64,...) |
3 | Date | YYYY-MM-DD |
4 | Time | HH:MM (24-hour) |
6 | Government ID upload | JSON { "name", "type", "data" } where data is an image data URL |
7 | Email address | |
8 | Phone | Phone number, 7 to 15 digits, formatting characters allowed |
9 | URL | Absolute http or https URL |
10 | Address | One formatted address line, at most 500 characters |
11 | Select | Exactly one option label from config.options |
12 | Multi-select | One or more option labels from config.options, joined with , |
Types 11 and 12 carry a config document:
{ "version": 1, "options": [ { "label": "Small", "description": "Up to 5ft" }, { "label": "Large" } ] }Answers are matched case-insensitively and stored using the operator's spelling, in the order the options are defined. Only multi-select labels forbid commas, so their answers can be split on , safely; select answers match one whole label. Choice answers allow 5,098 characters, enough for all 50 labels of up to 100 characters plus separators. config is absent on every other field type; treat unknown keys as ignorable and version as a writer marker while reading compatible properties. Creating a choice field or changing its type requires config. Updating an unchanged choice type without config preserves the stored document; an explicitly empty option list is rejected.
ActivityAgreement
| Field | Type | Description |
|---|---|---|
uuid | string | Agreement identifier |
title | string | Agreement title |
body | string | Agreement body text |
required | boolean | Whether the customer must accept |
enabled | boolean | Whether this agreement is active |
ActivityDynamicDurationSetting
| Field | Type | Description |
|---|---|---|
enabled | boolean | Whether dynamic durations are enabled |
minimumHours | number | Minimum bookable duration in hours |
maximumHours | number | Maximum bookable duration in hours |
incrementMinutes | number | Allowed increment (in minutes) between min and max |
baseHourlyRate | number | Hourly rate used for pricing |
createdAt | Date | Created timestamp |
updatedAt | Date | Last updated timestamp |
ActivityScheduling
| Field | Type | Description |
|---|---|---|
dateType | number | Date selection mode (range vs specific dates) |
dateRange | DateOnlyRange | Bookable date range (when dateType is range) |
specificDates | string[] | Bookable dates (when dateType is specific dates) |
earlyCutoffType | number | Cutoff unit (hours, days, etc.) |
earlyCutoffValue | number | How far in advance bookings must be made |
futureCutoffDays | number | How far into the future bookings can be made |
TripProtection
| Field | Type | Description |
|---|---|---|
enabled | boolean | Whether trip protection is offered |
pricingType | number | Pricing mode (flat amount vs percent) |
flatAmount | number | Flat fee when pricingType is flat |
percentAmount | number | Percentage when pricingType is percent |
coverageType | number | Coverage mode |
coverageAmount | number | Amount of coverage provided |
customTitle | string | Custom display title |
customDescription | string | Custom description shown to the customer |
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 (a departure with any existing booking is unavailable). Implied for activities with privateToursOnly. |
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 |
|---|---|---|
startDate | Date | Slot start (full datetime) |
endDate | Date | Slot end (full datetime) |
durationMinutes | number | Slot length in minutes |
price | number | Price for this time slot |
isAvailable | boolean | Whether this slot can be booked |
remainingSeats | number | Number of seats still available (tour activities) |
canBookPrivateTour | boolean | Whether a private tour can be booked at this time |
blackoutMessage | string | Operator-supplied reason the slot is unavailable, populated only when a location blackout blocks the slot. Activity-level blackouts do not surface a message. |
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.