Title
Page icon
Create new category
Edit page index title
Edit category
Edit link
Add-ons (v1.3)
v1.3
Add-Ons are optional - and occasionally mandatory (i.e., Disneyland Resorts®) - items that can be purchased alongside a base booking. They are configured by the Supplier at the Product, Rate, or traveler type level and range from consumables and equipment to experiences and upgrades.
Examples of real-world Add-ons: fast-lane pass, drink vouchers, meal packages, souvenir photographs, private guide upgrades, and mandatory equipment rentals.
🔗 Find the full details here: Reseller API Reference
v1.2 partners: Add-ons is a v1.3 only capability. Your existing integration is unaffected. You can adopt it at any time by switching to the /v1.3/ base path.
How to Request Add-ons
Add-ons are not returned by default. Pass addOns=true on any of the following endpoints to include them:
GET/suppliers/{supplier_id}/products/{product_id}/rates/{rate_id}
GET/suppliers/{supplier_id}/products/{product_id}/pricing/schedule → maximum 30-day date range
GET/suppliers/{supplier_id}/products/{product_id}/availabilities → maximum 30-day date range
GET/suppliers/{supplier_id}/products/{product_id}/availability → maximum 30-day date range
To also receive localized Add-on descriptions and media, combine both parameters: addOns=true & content=true.
Add-On Levels
Suppliers configure Add-ons at three levels of the Product hierarchy. The level controls which bookings the Add-on is available for and where addOns[] appears in the response.
Level | Where | Available for |
|---|---|---|
Product |
| All Rates and all traveler types under this Product |
Rate |
| All traveler types under this specific Rate only |
TravelerType |
| This specific traveler type (age band) only |
In the Price Schedule and Availability responses, Add-ons from all three levels are embedded together inside each slot. Use the rateId and unitId fields to identify which level each Add-on belongs to:
|
| Level |
|---|---|---|
No | No | Product-level |
Yes | No | Rate-level |
Yes | Yes | TravelerType (unit) level |
Understanding Data Presence (Read vs. Write)
As a channel manager, Travel Curious sits between the Supplier's ticketing system and your Reseller application. Because of this, it is important to distinguish between the data you receive from Suppliers versus the data you must send to us.
The indicators below describe what the Supplier is obligated to provide to Travel Curious. This helps you understand how reliable a field will be when you receive it in a GET response.
(Note: When you are sending data to us, such as in a POST /holds or POST /bookings request, you must still strictly follow the required fields defined in the API Reference schema).
General Field Presence Legend
What to expect in responses - This standard applies across all API capabilities
🟢 Always: Required from the Supplier. Your integration can safely assume this field will be present in the response and never be null. Note for Optional Capabilities: If the field belongs to an optional feature (like Add-ons, Booking Questions or Content), this guarantee applies only if that feature is present in the response.
🟠Conditional: Required from the Supplier, but only under specific circumstances. Its presence depends on context, such as the hierarchy level or a dependency on another field.
🟡 Occasional: Completely optional for the Supplier to provide. Your integration must handle nulls or missing keys gracefully.
💡 Developer Note for Add-ons: Because the existence of an Add-on is entirely dependent on whether a Supplier offers them, no fields within the Add-on schemas are universally guaranteed. You must always check if the
addOns[]array exists before parsing its contents. The indicators below apply only after confirming an Add-on is present.
Add-ons Object Fields
Field | Type | Description | Presence |
|---|---|---|---|
| string | Unique identifier for this Add-on. | 🟢 Always |
| string | Add-on internal name for back-office use | 🟢 Always |
| string | Add-on customer-facing display name | 🟡 Occasional |
| string | Details about the Add-on for display in your UI | 🟡 Occasional |
| string | Add-on internal code used by the Supplier for operational reference | 🟡 Occasional |
| AddOnScope | How the Add-on applies at booking time (see Scope section below) | 🟢 Always |
|
| Add-on purchase limits and eligibility restrictions | 🟡 Occasional |
|
| The Add-on ticket code formats (e.g., | 🟡 Occasional |
|
| The Add-on delivery method. | 🟡 Occasional |
| RedemptionMethod | How the guest redeems the Add-on at the venue. A value of MANIFEST indicates that the customer MUST provide a form of identification to redeem and as such a printed or digital copy of the ticket is | 🟡 Occasional |
| Policy | Add-on policy information related to holds and bookings | 🟡 Occasional |
| Content | Localized descriptions, media, and features - same Content object used across the API | 🟡 Occasional |
| Extensions | Key-value map for additional partner-specific data | 🟡 Occasional |
Scope
scope defines the unit at which the Add-on is purchased. This determines how many times it must be selected and how quantity is calculated.
Scope | Applies to | UI pattern | Example |
|---|---|---|---|
| Once per product in the booking | Single selection, applies automatically | Family photo taken once at the venue |
| Once per booking, regardless of guest count | Toggle or quantity counter | Private guide upgrade, group drink vouchers |
| Once per traveler in the booking | Guest-level selection, or auto-applied per guest | Bottle of water, mandatory equipment rental |
| Once per day of the experience | Date-aware quantity | Parking pass |
Constraints and Purchase Limits
Suppliers can define specific restrictions on how many Add-ons can be purchased (e.g., requiring exactly one harness per guest, or capping drink vouchers at 10 per booking). When these restrictions apply, they are returned in the constraints[] array on the Add-on object.
🔗 See the full Traveler Type Constraints documentation for a complete list of constraint types, JSON payload examples, and UI implementation guidance on how to enforce min and max limits in your application.
Availability with Add-ons
When addOns=true is included in an availability request, each availability slot in the response carries an embedded addOns[] array. Each entry is an AddOnAvailability object.
AddOnAvailability Schema
Field | Type | Description | Presence |
|---|---|---|---|
| string | Unique ID for this Add-on avail slot. | 🟢 Always |
| string | The ID of the Add-on this availability entry refers to | 🟢 Always |
| string | Present if this is a rate-level Add-on | 🟡 Occasional - Present only if this is a Rate-level |
| string | Present if this is a traveler/unit level Add-on | 🟡 Occasional - Present only if this is a Traveler Type (unit) level |
| ISO 8601 | The start time for the Add-on | 🟢 Always |
| ISO 8601 | The end time for the Add-on | 🟢 Always |
| AvailabilityStatus |
| 🟢 Always |
| integer | The current number of Add-ons available | 🟡 Occasional |
| integer | Maximum configured capacity for this Add-on | 🟡 Occasional |
| string | Add-on description | 🟡 Occasional |
| Extensions | Key-value map for additional partner-specific data | 🟡 Occasional |
The first Add-on (
addon-photo-pkg) has norateIdorunitId→ it is a product-level Add-on.The second (
addon-llmp) has arateId→ it is a rate-level Add-on.The third (
addon-harness) has bothrateIdandunitId→ it is a traveler type level Add-on.
Price Schedule with Add-Ons
When addOns=true is included in a Price Schedule request, each PriceScheduleItem carries an embedded addOns[] array of AddOnPrice objects.
Add-ons are not gap-filled. Unlike standard Rate prices, Add-on prices must always come from the Price Schedule, they will not fall back to static Rate-level data if no scheduled price exists.
AddOnPrice Schema
💡 Pricing Amounts Note: While the
net,retail, andoriginalprice fields are individually marked as 🟠Conditional, the Supplier is required to provide at least one of these three fields. Your integration should check which price format was provided and fall back accordingly.
Field | Type | Description | Presence |
|---|---|---|---|
| string | Unique identifier for the add-on price. | 🟢 Always |
| string | The ID of the parent AddOn this price belongs to. | 🟢 Always |
| string | Present if this is a rate-level Add-on price | 🟡 Occasional - Present only if this is a Rate-level |
| string | Present if this is a traveler type (unit) level Add-on price | 🟡 Occasional - Present only if this is a Traveler Type (unit) level |
| ISO 8601 | The start time for the Add-on price | 🟢 Always |
| ISO 8601 | The end time for the Add-on price | 🟢 Always |
| Price | The net price for this Add-on. The wholesale amount owed to the Supplier by the Reseller | 🟠Conditional - Present only if provided by Supplier. (See Pricing Amount note above). |
| Price | The retail price for the Add-on. The recommended selling price for the guest, inclusive of any applied discounts. This is the final price the guest pays | 🟠Conditional - Present only if provided by Supplier. (See Pricing Amount note above). |
| Price | The original price for the Add-on. The original price before any discounts are applied. Used to display a strike-through price in the UI | 🟠Conditional - Present only if provided by Supplier. (See Pricing Amount note above). |
| IncludedTaxes[] | Taxes and Fees already embedded in the Add-on price | 🟠Conditional - Present only if provided by Supplier. (See Pricing Amount note above). |
| string | Add-on description | 🟡 Occasional |
| Extensions | Key-value map for additional partner-specific data | 🟡 Occasional |
Submitting Add-Ons in a Hold
Add-Ons are submitted as an addOns[] array at the same level as the Hold items[] array. The same AddOnItem structure is used for both Hold and Booking.
💡 Submission Rule: Price fields within the
AddOnItemobject (net,retail,original) must be populated by the Reseller, representing the actual price at which the Add-on was sold. Travel Curious will not automatically inject or calculate this data during the Hold or Booking stages. You must always source the correct price format from the Price Schedule response prior to submitting the payload.
AddOnItem Schema (Holds & Bookings)
Field | Type | Description | Presence |
|---|---|---|---|
| string | Unique identifier for the add-on item. | 🟢 Always |
| string | The ID of the Add-on being purchased | 🟢 Always |
| integer | Number of Add-ons being purchased | 🟢 Always |
| ISO 8601 | The start time slot for the Add-on | 🟢 Always |
| ISO 8601 | The end time slot for the Add-on | 🟢 Always |
| string | The parent Supplier ID | 🟢 Always |
| string | The parent Product ID | 🟢 Always |
| string | Present if this is a rate-level Add-on price | 🟡 Occasional - Present only if this is a Rate-level |
| string | Present if this is a traveler type (unit) level Add-on price | 🟡 Occasional - Present only if this is a Traveler Type (unit) level |
| Price | The net price (wholesale amount) owed to the Supplier by the Reseller for this Add-on. | 🟡 Occasional IMPORTANT: Price fields within the |
| Price | The final retail price paid by the guest for the Add-on. | 🟡 Occasional IMPORTANT: Price fields within the |
| Price | The original price for the Add-on. The original price before any discounts are applied. Used to display a strike-through price in the UI | 🟡 Occasional IMPORTANT: Price fields within the |
| string | Your internal reference for this Add-on item | 🟡 Occasional - recommended to be provided by the Reseller in the request |
| string | An optional reference ID provided by the Supplier for this add-on item. | 🟡 Occasional - Only returned on the response |
| Barcode[] | The associated barcodes for the Add-ons. | 🟡 Occasional - Only returned on the booking response |
| Extensions | Key-value map for additional partner-specific data | 🟡 Occasional |
The Hold response echoes back the addOns[] array exactly as submitted.
Submitting Add-Ons in a Booking
The Booking request uses the same AddOnItem structure and the same addOns[] array at the same level as items[].
The Booking response echoes back addOns[] and may include barcodes[] on each AddOnItem when the Supplier provides them at booking confirmation.
Barcode and Ticket Delivery
Add-ons can either share a single ticket with the base booking or require their own separate tickets. Because Add-ons have their own deliveryMethods array (independent of the main product), you must check the deliveryMethods array on the AddOn object to understand how barcodes will be issued.
Delivery Method | How it works | When to use |
|---|---|---|
| A single barcode covers the entire booking, including all base booking items and all Add-on items | When the Supplier issues one shared redemption code for everything |
| Individual barcodes are issued for every base booking item and every individual Add-on item. | When each specific item and add-on requires its own scan at the venue |
Barcodes at intermediate or mixed levels are not supported. Add-on barcodes must be either at the top booking level (
VOUCHER) or at the individual item level (TICKET). Check thedeliveryMethodsarray on the specificAddOnobject to determine which model applies to that Add-on, and ensure your ticket rendering logic handles both cases.
Pro-Tips & Edge Cases
Handling FREESALE Capacity: Add-on availability slots will return a
statusof eitherAVAILABLEorFREESALE. If an Add-on isFREESALE(meaning it has unlimited capacity), thevacanciesandmaxCapacityfields may be entirely omitted from the response. Ensure your parsers and UI logic do not break if these integers are missing.Submitting Taxes: When submitting the
net,retail, andoriginalprices in your Hold or Booking request, check if the Price Schedule included anincludedTaxes[]array for that Add-on. If it did, you should echo that array back in yourAddOnItempayload to ensure accurate financial reporting.Add-Ons and Cancellations: Add-Ons cannot currently be cancelled independently of their base item. Cancelling a Booking cancels any associated Add-Ons along with it - there is no partial/add-on-only cancellation at this time.
Use Cases
Booking-Scoped, Single Unit
Scenario: A boat tour is $50 per person. A group of 5 people wants a private guide. The guide costs a flat $100 for the whole group, and you only have 1 guide available per departure.
Level: Rate (The specific time slot)
Scope:
booking(Applies once to the whole reservation)Constraint (
PurchaseLimit):Min: 0 (Optional)
Max: 1 (You can't hire two guides for one boat)
Business Logic: Even though there are 5 guests, the API calculates: (5 x $50) + (1 x $100) = $350. The UI shows a toggle switch.
Quantity Counter - Booking-Scoped, Flexible Quantity
Scenario: At a live music event, guests can pre-purchase "Drink Vouchers" at a discount. A group of 4 people wants to buy 10 vouchers to share.
Level:
Product(Available for all show times)Scope:
booking(Not tied to a specific person's ticket)Constraint (
PurchaseLimit):Min: 1
Max: 20 (Limit per group to prevent bulk resale)
Business Logic: The user sees a quantity counter (+/-). They select "10". The API validates that 10 is less than 20 and calculates the price for the 10 vouchers regardless of the 4-person party size.
Auto-Applied, Non-Removable - Guest-Scoped, Mandatory
Scenario: A zip-lining tour requires a "Full Body Harness." For insurance reasons, every single participant must rent one, and the price is $10 per person.
Level:
Traveler Type / Unit(Applied to every "Guest")Scope:
guest(Must be assigned to a specific person)Constraint (
PurchaseLimit):Min: 1 (Required)
Max: 1 (One person cannot wear two harnesses)
Business Logic: The UI automatically selects this for every guest and disables any "Remove" button. If 5 guests are booked, the API calculates $5 x $10 = $50.
Questions? We'd love to hear them. Contact Travel Curious Support.