In this guide, we cover:
Pricing structure in the API
Verify the pricing of all Viator products and calculate the pricing for a specific date, product option, start time and passenger mix
Ingesting & updating data
Easily ingest availability and pricing schedules
Per person and unit pricing
Identify the lowest per-person price for a product, as well as the exact price based on the total passenger count, calculated either per person or per group
Special pricing
Promote special offers
Currency conversion
Convert pricing between multiple currencies
Low margin products
Ensure that your pricing aligns with current industry standards for pricing and calculate the exact amount that will be invoiced by Viator
Real time pricing checks
Verify real-time pricing
Pricing hold
Make an availability and pricing hold (for a limited period of time)
Invoicing
Check the exact amount you will be invoiced and the refund amount in case of a booking cancellation
Extra charges
Inform your customers about extra charges paid in destination (if applicable)
As a merchant partner, you are free to decide on the pricing that will apply to Viator products sold to your customers. However, it is essential to verify the exact cost to you in order to keep the industry standards and make sure that you can make a profit from your bookings.
Do you know which pricing model applies to your solution?
Ensure you are aware of the pricing model that applies to your solution, as the API pricing structure varies based on the solution used:
- Markup model – the partner sets the markup on their end and is invoiced the partnerTotalPrice (partnerNetPrice + bookingFee). Applicable only to merchant API partners who select the markup model.
- Commission model – the partner sells at the recommendedRetailPrice and receives a percentage commission for each booking. Applicable to all affiliate API partners with booking access and to merchant API partners who select the commission model.
To avoid confusion, make sure you confirm commercial details with your team. This will be specified in your contract.
Pricing structure in the API
Structured pricing information is provided by the API via the availability schedules endpoints. It consists of the following elements:
pricingPackageType – pricing type for this product; one of:
- “PER_PERSON” – pricing is calculated per-person,
- “UNIT” – pricing is calculated per-group/unit with the following options available for “unitType”: “GROUP”, “ROOM”, “PACKAGE”, “VEHICLE”, “BIKE”, “BOAT”, “AIRCRAFT” (other unit types might be added in the future).
maxTravelers – maximum number of travelers allowed to book for this price to apply
- “ADULT”
- “SENIOR”
- “YOUTH”
- “CHILD”
- “INFANT”
- “TRAVELER”
commission – the amount that you will keep for this sale in case you are an affiliate partner with booking access or have a commission merchant agreement (please note: commission doesn’t apply to markup merchants who are invoiced the merchant net rate + the booking fee)
partnerNetPrice – the amount that Viator will invoice you for this sale, excluding the booking fee (if you are a markup merchant)
bookingFee – the fee Viator will invoice you for the sale (if you are a markup merchant) and should be included in the final price charged to the end customer. Your bookingFee is a percentage that is specified in your contract with Viator.
partnerTotalPrice – the total amount that Viator will invoice you for this sale, including the transaction fee (if you are a markup merchant)
offerStartDate and offerEndDate fields are returned to indicate the period during which the offer applies. For example, a special offer applies when you make the booking between 1 and 15 March, for any travel date
travelStartDate and travelEndDate fields are used to indicate the period during which the tour must be completed. For example, if you book for travel date between 1 and 15 March you get a discounted rate but the special pricing wouldn’t apply if you book after 15 March
fromPriceBeforeDiscount – if the product is presently discounted, this field shows what the value of fromPrice would be if no discount had been applied; otherwise, it will be absent.
extraChargesSummary – the summary of extra charges to be paid by the customer in destination for all bookable items, including mandatory charges broken down by item, number of units, amount per unit and the total amount – in the currency provided in the request and converted into the currency in destination (if different from request currency)
extraCharges – the maximum value of extra charges to be paid by the customer in destination
mandatory – object with all mandatory extra charges to be paid in destination, includes: charge name, number of units (number of times it has to be calculated, i.e. per person, per group), amount per unit, total amount – in the currency provided in the request and converted into the currency in destination (if different from request currency)
Example response for product 100912P8 (markup model)
{
“productCode”: “100912P8”,
“bookableItems”: [
{
“productOptionCode”: “TG1”,
“seasons”: [
{
“startDate”: “2019-08-08”,
“pricingRecords”: [
{
“daysOfWeek”: [
“MONDAY”,
“TUESDAY”,
“WEDNESDAY”,
“THURSDAY”,
“FRIDAY”,
“SATURDAY”,
“SUNDAY”
],
“timedEntries”: [
{
“startTime”: “09:00”,
“unavailableDates”: [
{
“date”: “2022-05-02”,
“reason”: “SOLD_OUT”
},
{
“date”: “2022-04-13”,
“reason”: “SOLD_OUT”
},
{
“date”: “2022-05-01”,
“reason”: “SOLD_OUT”
}
]
}
],
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “INFANT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 100.00,
“partnerNetPrice”: 79.88,
“bookingFee”: 5.19,
“partnerTotalPrice”: 85.07
},
“special”: {
“recommendedRetailPrice”: 95.00,
“partnerNetPrice”: 75.89,
“bookingFee”: 4.93,
“partnerTotalPrice”: 80.82,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 100.00,
“partnerNetPrice”: 79.88,
“bookingFee”: 5.19,
“partnerTotalPrice”: 85.07
},
“special”: {
“recommendedRetailPrice”: 90.00,
“partnerNetPrice”: 71.89,
“bookingFee”: 4.67,
“partnerTotalPrice”: 76.56,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “YOUTH”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 159.75,
“bookingFee”: 10.38,
“partnerTotalPrice”: 170.13
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 143.78,
“bookingFee”: 9.34,
“partnerTotalPrice”: 153.12,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 159.75,
“bookingFee”: 10.38,
“partnerTotalPrice”: 170.13
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 143.78,
“bookingFee”: 9.34,
“partnerTotalPrice”: 153.12,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “SENIOR”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 159.75,
“bookingFee”: 10.38,
“partnerTotalPrice”: 170.13
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 143.78,
“bookingFee”: 9.34,
“partnerTotalPrice”: 153.12,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
}
]
}
]
}
]
}
],
“currency”: “EUR”,
“summary”: {
“fromPrice”: 180.00
}
}
Example response for product 100912P8 (commission model)
{
“productCode”: “100912P8”,
“bookableItems”: [
{
“productOptionCode”: “TG1”,
“seasons”: [
{
“startDate”: “2019-08-08”,
“pricingRecords”: [
{
“daysOfWeek”: [
“MONDAY”,
“TUESDAY”,
“WEDNESDAY”,
“THURSDAY”,
“FRIDAY”,
“SATURDAY”,
“SUNDAY”
],
“timedEntries”: [
{
“startTime”: “09:00”,
“unavailableDates”: [
{
“date”: “2022-05-02”,
“reason”: “SOLD_OUT”
},
{
“date”: “2022-04-13”,
“reason”: “SOLD_OUT”
},
{
“date”: “2022-05-01”,
“reason”: “SOLD_OUT”
}
]
}
],
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “INFANT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 100.00,
“partnerNetPrice”: 90.00,
“bookingFee”: 0,
“commission”: 10.00,
“partnerTotalPrice”: 90.00
},
“special”: {
“recommendedRetailPrice”: 95.00,
“partnerNetPrice”: 85.50,
“bookingFee”: 0,
“commission”: 9.50,
“partnerTotalPrice”: 85.50,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 100.00,
“partnerNetPrice”: 90.00,
“bookingFee”: 0,
“comission “: 10.00,
“partnerTotalPrice”: 90.00
},
“special”: {
“recommendedRetailPrice”: 90.00,
“partnerNetPrice”: 81.00,
“bookingFee”: 0,
“commission”: 9.00,
“partnerTotalPrice”: 81.00,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “YOUTH”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 180.00,
“bookingFee”: 0,
“commission”: 20.00,
“partnerTotalPrice”: 180.00
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 162.00,
“bookingFee”: 0,
“commission”: 18.00,
“partnerTotalPrice”: 162.00,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 180.00,
“bookingFee”: 0,
“commission”: 20.00,
“partnerTotalPrice”: 180.00
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 162.00,
“bookingFee”: 0,
“commission”: 18.00,
“partnerTotalPrice”: 162.00,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “SENIOR”,
“price”: {
“original”: {
“recommendedRetailPrice”: 200.00,
“partnerNetPrice”: 180.00,
“bookingFee”: 0,
“commission”: 20.00,
“partnerTotalPrice”: 180.00
},
“special”: {
“recommendedRetailPrice”: 180.00,
“partnerNetPrice”: 162.00,
“bookingFee”: 0,
“commission”: 18.00,
“partnerTotalPrice”: 162.00,
“offerStartDate”: “2022-03-19”,
“offerEndDate”: “2022-05-17”,
“travelStartDate”: “2022-03-20”,
“travelEndDate”: “2022-08-20”
}
}
}
]
}
]
}
]
}
],
“currency”: “EUR”,
“summary”: {
“fromPrice”: 180.00
}
}
Based on the example above, the same product might offer different pricing depending on the productOptionCode, seasons, startTime, or ageBand.
Ingesting and updating pricing data
The /availability/schedules/modified-since endpoint allows you to ingest all availability and pricing data and keep it updated on your end.
Detailed instructions for the ingestion process can be found in our Technical guide and this article: Managing product and availability data.
The more frequently this data is updated on your end, the better. To ensure the data stays accurate and up-to-date, we recommend updating availability and pricing schedules at least once an hour. Updates must be ingested at least hourly.
In case you don’t wish to ingest the full product catalog but prefer to pull availability for a single product when the customer selects a product from the search results, use the /availability/schedules/{product-code} endpoint. The response can be cached for up to 1 hour but this endpoint must not be used to ingest schedules for all products.
For cases where an exception has been approved for the use of bulk endpoints (<10k products), you could use the /availability/schedules/bulk endpoint.
The rates returned from the /availability/schedules/* endpoints are provided in the supplier’s currency. In order to convert the rates between currencies and check the rates in the currency in which you will charge your customers, you need to use the /exchange-rates endpoint (or your own exchange rates system). For additional information about currency conversion check the currency conversion section.
The data returned from the /availability/schedules endpoints should be ingested and used to display the initial pricing, for example in the calendar view before users select a specific date:

Please note:
- The /availability/check endpoint is not intended for bulk ingestion of availability and pricing data. It is designed for real-time checks only.
- You shouldn’t expect to be invoiced based on the pricing returned with /availability/schedules endpoints as this is cached data. That’s why real-time availability and pricing checks with the /availability/check endpoint must be conducted prior to booking in order to get fully accurate pricing.
Per person and unit pricing
Viator pricing can be grouped into two categories: per person pricing and unit pricing – indicated in the pricingPackageType field of the product content response with the value either “PER_PERSON” or “UNIT”.
Per-person pricing
Per-person pricing is calculated based on the number of participants from each age band (to read more about the Viator age bands, check this article). The pricing is returned separately for each age band, as shown in the response example.
Example response (markup model)
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “INFANT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 0.00,
“partnerNetPrice”: 0.00,
“bookingFee”: 0.00,
“partnerTotalPrice”: 0.00
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 80.11,
“partnerNetPrice”: 66.46,
“bookingFee”: 4.32,
“partnerTotalPrice”: 70.78
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 4,
“maxTravelers”: 4,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 80.11,
“partnerNetPrice”: 66.46,
“bookingFee”: 4.32,
“partnerTotalPrice”: 70.78
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 2,
“maxTravelers”: 2,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 92.43,
“partnerNetPrice”: 76.68,
“bookingFee”: 4.98,
“partnerTotalPrice”: 81.66
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 154.05,
“partnerNetPrice“: 127.80,
“bookingFee”: 8.31,
“partnerTotalPrice”: 136.11
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 3,
“maxTravelers”: 3,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 87.30,
“partnerNetPrice”: 72.42,
“bookingFee”: 4.71,
“partnerTotalPrice”: 77.13
}
}
}
]
Example response (commission model)
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “INFANT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 0.00,
“partnerNetPrice”: 0.00,
“bookingFee”: 0.00,
“commission”: 0.00,
“partnerTotalPrice”: 0.00
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 80.11,
“partnerNetPrice”: 72.10,
“bookingFee”: 0,
“commission”: 8.01,
“partnerTotalPrice”: 72.10
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 4,
“maxTravelers”: 4,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 80.11,
“partnerNetPrice”: 72.10,
“bookingFee”: 0,
“commission”: 8.01,
“partnerTotalPrice”: 72.10
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 2,
“maxTravelers”: 2,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 92.43,
“partnerNetPrice”: 83.19,
“bookingFee”: 0,
“commission”: 9.24,
“partnerTotalPrice”: 83.19
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“maxTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 154.05,
“partnerNetPrice“: 138.65,
“bookingFee”: 0,
“commission”: 15.40,
“partnerTotalPrice”: 138.65
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 3,
“maxTravelers”: 3,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 87.30,
“partnerNetPrice”: 78.57,
“bookingFee”: 0,
“commission”: 8.73,
“partnerTotalPrice”: 78.57
}
}
}
]
The same age band might have different pricing depending on the number of participants from that age band.
As illustrated in the example above for product 40856P10, the per-person pricing for an ADULT age band is much higher when only one adult is booked than in the scenario where multiple adults are booked.
The lowest per-person retail price for the product is returned as fromPrice in the response from the /availability/schedules/* endpoints (in the currency provided by the supplier). It’s calculated according to the price for a group of at least two standard participants (or, the smallest bookable group if more than two participants are required) for a period not exceeding 384 days into the future. This value can be used to advertise a ‘from’-price.
Example response
{
“currency”: “THB”,
“summary”: {
“fromPrice”: 2900.00
}
}
Unit pricing
Unit pricing is based on the number of groups (units) and types of groups (units) that could be either: “GROUP”, “ROOM”, “PACKAGE”, “VEHICLE”, “BIKE”, “BOAT”, or “AIRCRAFT” – all defined in the API documentation:
Example response
“pricingInfo”: {
“type”: “UNIT”,
“ageBands”: [
{
“ageBand”: “TRAVELER”,
“startAge”: 0,
“endAge”: 99,
“minTravelersPerBooking”: 1,
“maxTravelersPerBooking”: 15
}
],
“unitType”: “VEHICLE”
},
The pricing information can be retrieved from the /availability/schedules/* endpoints:
Example response (markup model)
“pricingDetails”: [
{
“pricingPackageType”: “UNIT”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “TRAVELER”,
“price”: {
“original”: {
“recommendedRetailPrice”: 500.00,
“partnerNetPrice”: 392.99,
“bookingFee”: 25.54,
“partnerTotalPrice”: 418.53
}
}
}
]
Example response (commission model)
“pricingDetails”: [
{
“pricingPackageType”: “UNIT”,
“minTravelers”: 1,
“maxTravelers”: 15,
“ageBand”: “TRAVELER”,
“price”: {
“original”: {
“recommendedRetailPrice”: 500.00,
“partnerNetPrice”: 450.00,
“bookingFee”: 0,
“commission”: 50.00,
“partnerTotalPrice”: 450.00
}
}
}
]
The price for two travelers would be exactly the same as the price for four travelers, because the price is based on the number of units and not the number of travelers.
In order to book this product for more than four travelers, a new booking request would need to be made (the API doesn’t support multiple bookings at the same time).
Please note: unit pricing is linked to only one age band – TRAVELER (this age band will not appear for products that have per-person pricing).
You can read more about per-person vs unit pricing in this section of the API documentation.
Special pricing
Some Viator suppliers offer discounted pricing for their products – this information is returned in the API under “special” pricing. Special pricing is valid only for a time period specified, and sometimes it applies to specific travel dates.
There are additional attributes linked to special pricing that must be used to validate the pricing correctly:
- offerStartDate and offerEndDate fields are returned to identify the period when the offer applies, for example a special offer applies when you make the booking between March 1st-15th, for any travel date
- travelStartDate and travelEndDate fields are used to indicate the period within which the tour should be completed, for example if you book for travel date between March 1st-15th you get a discounted rate but the special pricing won’t apply if your travel date is after 15 March
For example, the pricing schedule below for the product 195878P21 indicates that the special offer applies to the CHILD age band for bookings made between 2 April and 31 May 2022, for any travel date between 2 April and 31 October 2022.
Example response (markup model)
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 45.00,
“partnerNetPrice”: 38.34,
“bookingFee”: 2.49,
“partnerTotalPrice”: 40.83
},
“special”: {
“recommendedRetailPrice”: 36.00,
“partnerNetPrice”: 30.67,
“bookingFee”: 1.99,
“partnerTotalPrice”: 32.66,
“offerStartDate”: “2022-04-02”,
“offerEndDate”: “2022-05-31”,
“travelStartDate”: “2022-04-02”,
“travelEndDate”: “2022-10-31”
}
}
}
Example response (commission model)
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 45.00,
“partnerNetPrice”: 40.50,
“bookingFee”: 0,
“commission”: 4.5,
“partnerTotalPrice”: 40.50
},
“special”: {
“recommendedRetailPrice”: 36.00,
“partnerNetPrice”: 32.40,
“bookingFee”: 0,
“commission”: 3.60,
“partnerTotalPrice”: 32.40,
“offerStartDate”: “2022-04-02”,
“offerEndDate”: “2022-05-31”,
“travelStartDate”: “2022-04-02”,
“travelEndDate”: “2022-10-31”
}
}
}
Please note:
- You will always see the offerStartDate and offerEndDate returned for special pricing and depending on the supplier’s set up you may or may not see the travelStartDate and travelEndDate returned – this depends if the supplier wants to apply the offer to all future dates or only specific dates.
- Special pricing is defined on a per-age-band basis. It’s possible to get special pricing for the same product only for selected age bands (i.e. special pricing is returned for an adult age band but not for a child age band).
Unlocking the value of discounted rates
Special offers and discounts are effective tools for attracting customer attention and boosting sales. Leveraging them can significantly enhance customer engagement and conversion rates. It’s highly recommended to incorporate special offers, discounts, and promotions into your pricing strategy to drive more traffic and increase sales opportunities.
Additional tools for identifying discounted rates
- You can also identify products with permanently discounted rates using the Viator tags. For example:
- “tagId”: 12493 – “Discounted Pricing for Select Groups”
- “tagId”: 12461 – “Discounted Pricing for Children”
- “tagId”: 12462 – “Discounted Pricing for Seniors”
- “tagId”: 12463 – “Discounted Pricing for Students”
- “tagId”: 12464 – “Discounted Pricing for Veterans”
Feel free to read more about the Viator tags and how to use them to merchandise products in this article.
Pricing could be modified by the supplier at any time therefore it’s recommended to always verify if the product offers special pricing based on the pricing schedules returned in the API.
Low margin products (markup merchants)
You can easily check the price of the activity on Viator – it’s returned in the API as the recommendedRetailPrice.
However, in some rare cases the recommendedRetailPrice might be lower than the partnerTotalPrice (the total amount that you will be invoiced if you are a markup merchant). This means that selling a product at the recommended retail price without first confirming that the margin is acceptable could result in a net loss for that transaction. This would apply to low margin products on Viator and only to markup merchants (the value of partnerTotalPrice and partnerNetPrice will always be equal for commission merchants).
Therefore if you are a markup merchant, it’s important for you to have logic in place to compare the recommendedRetailPrice and the partnerTotalPrice and adjust the pricing if necessary to make sure that selling at the recommendedRetailPrice wouldn’t result in a loss.
For example, product 3328DISNEY returns the recommendedRetailPrice higher than the partnerTotalPrice for both ADULT and CHILD age bands:
Example response (markup model)
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 520.00,
“partnerNetPrice”: 492.88,
“bookingFee”: 32.04,
“partnerTotalPrice”: 524.92
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 540.00,
“partnerNetPrice”: 511.84,
“bookingFee”: 33.27,
“partnerTotalPrice”: 545.11
}
}
}
]
}
]
Example response (commission model)
“pricingDetails”: [
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “CHILD”,
“price”: {
“original”: {
“recommendedRetailPrice”: 520.00,
“partnerNetPrice”: 468.00,
“bookingFee”: 0,
“commission”: 52.00,
“partnerTotalPrice”: 468.00
}
}
},
{
“pricingPackageType”: “PER_PERSON”,
“minTravelers”: 1,
“ageBand”: “ADULT”,
“price”: {
“original”: {
“recommendedRetailPrice”: 540.00,
“partnerNetPrice”: 486.00,
“bookingFee”: 0,
“commission”: 54.00,
“partnerTotalPrice”: 486.00
}
}
}
]
}
]
To make sure that you make a profit on that product, you will need to adjust the pricing on your end so that it’s not lower than the partnerTotalPrice.
Currency conversion
The availability schedules endpoints return rates in the currency provided by the supplier. The following supplier currencies are supported: AED, AUD, BRL, CAD, CHF, CNY, DKK, EUR, FJD, GBP, HHL, HKD, IDR, INR, ISK, JPY, KRW, MXN, MYR, NOK, NZD, PLN, RUB, SEK, SGD, THB, TRY, TWD, USD, VND, ZAR.
If you don’t have your own exchange rate system, you must use the /exchange-rates endpoint to convert pricing into the currency you wish to be invoiced in (AUD, CAD, EUR, GBP, or USD).
For example, in order to check the conversion rate from THB to USD, you need to make the following request:
Example request
curl –location -g –request POST ‘{{papi_host}}/exchange-rates’ \
–header ‘Accept: application/json;version={{version}}’ \
–header ‘Content-Type: application/json’ \
–header ‘exp-api-key: xxxx’ \
–data-raw ‘{
“sourceCurrencies”: [
“THB”
],
“targetCurrencies”: [
“USD”
]
}’
In the response, you will receive:
Example response
{
“rates”: [
{
“sourceCurrency”: “THB”,
“targetCurrency”: “USD”,
“rate”: 0.03190690376500000000,
“lastUpdated”: “2022-02-18T07:00:09Z”,
“expiry”: “2022-02-20T07:05:09Z”
}
]
}
The expiry field returns a timestamp (UTC) that indicates until when the conversion rate is valid. We request that you store the conversion rates data and refresh it periodically by checking the expiry timestamp. Currently, exchange rates are updated daily via the API, but this frequency may change in the future. The same conversion rate applies to all products, so there is no need to verify it for each booking separately.
It’s also important to do the real-time availability check with the /availability/check endpoint in the correct currency (for example “currency”: “USD” must be sent in the request body). This way you will be able to verify the exact amount that Viator will invoice you based on Viator exchange rates.
Real time pricing checks
Before the user makes a booking, it’s necessary to verify the pricing in real-time with the /availability/check endpoint. This could be done either when the user is moving to the checkout page, or as soon as they select a specific date and passenger mix (read more about the Viator age bands here).
Please note:
- This endpoint may only be used to check live availability on a per-product basis once a passenger mix and travel date have been selected.
- You should never use the availability real-time request (/availability/check) for bulk ingestion purposes.
- The request to the /availability/check endpoint should specify the currency in which you wish to be invoiced by Viator.The hold endpoint must never be used to check availability or price. Holds should only be placed after availability and pricing have been verified in real-time with the /availability/check endpoint.
(See our certification requirements)
Example request
{
“productCode”: “5096LASNIGHT”,
“travelDate”: “2022-08-26”,
“currency”: “USD”,
“paxMix”: [
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1
},
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1
}
]
}
The response returns all product options for the requested date and passenger mix:
Example response (markup model)
{
“currency”: “USD”,
“productCode”: “5096LASNIGHT”,
“travelDate”: “2022-08-26”,
“bookableItems”: [
{
“productOptionCode”: “TG3”,
“startTime”: “22:15”,
“available”: false,
“unavailableReason”: “TRAVELER_MISMATCH”
},
{
“productOptionCode”: “TG2”,
“startTime”: “19:15”,
“available”: false,
“unavailableReason”: “TRAVELER_MISMATCH”
},
{
“productOptionCode”: “TG1”,
“startTime”: “19:00”,
“available”: true,
“lineItems”: [
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 44.99,
“partnerNetPrice”: 31.14
}
},
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 49.99,
“partnerNetPrice”: 34.60
}
}
}
],
“totalPrice”: {
“price”: {
“recommendedRetailPrice”: 94.98,
“partnerNetPrice”: 65.74,
“bookingFee”: 4.27,
“partnerTotalPrice”: 70.01
}
}
}
]
}
Example response (commission model)
{
“currency”: “USD”,
“productCode”: “5096LASNIGHT”,
“travelDate”: “2022-08-26”,
“bookableItems”: [
{
“productOptionCode”: “TG3”,
“startTime”: “22:15”,
“available”: false,
“unavailableReason”: “TRAVELER_MISMATCH”
},
{
“productOptionCode”: “TG2”,
“startTime”: “19:15”,
“available”: false,
“unavailableReason”: “TRAVELER_MISMATCH”
},
{
“productOptionCode”: “TG1”,
“startTime”: “19:00”,
“available”: true,
“lineItems”: [
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 44.99,
“partnerNetPrice”: 40.49
}
},
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 49.99,
“partnerNetPrice”: 44.99
}
}
}
],
“totalPrice”: {
“price”: {
“recommendedRetailPrice”: 94.98,
“partnerNetPrice”: 85.48,
“bookingFee”: 0.00,
“commission”: 9.50,
“partnerTotalPrice”: 85.48
}
}
}
]
}
Availability and pricing hold
We highly recommend using the /bookings/hold or the /bookings/cart/hold endpoint during the booking process in order to place a temporary hold on availability and price. This way customers will be given enough time to fill in all required information and book before the product gets sold out or the price changes.
Please note:
- It’s essential to verify the timestamps returned in the API response for availability and pricing holds. A new hold can be placed only once the previous hold expires.
- A booking hold should not be made until the user has indicated a strong intention to book. Typically, this means that it should not be called until immediately prior to the user entering their payment details.
- The /bookings/hold or the /bookings/cart/hold endpoint must never be used to check product availability.
- All data included in a booking request (passenger mix, travel date, booking questions, etc.) must be validated for the product in question before an availability or pricing hold or booking request is made.
(See our certification requirements)
Example request
{
“productCode”: “85890P5”,
“startTime”: “06:00”,
“travelDate”: “2022-06-10”,
“currency”: “EUR”,
“paxMix”: [
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1
},
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1
}
]
}
The response includes the booking reference that should be used in the /bookings/book request, the status of availability and pricing holds as well as timestamps for each one (validUntil) and the pricing information:
Example response (markup model)
{
“bookingRef”: “BR-872448818”,
“bookingHoldInfo”: {
“availability”: {
“status”: “HOLDING”,
“validUntil”: “2022-04-13T13:05:55Z”
},
“pricing”: {
“status”: “HOLDING”,
“validUntil”: “2022-04-13T13:05:55.422456Z”
}
},
“currency”: “EUR”,
“lineItems”: [
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 73.13,
“partnerNetPrice”: 59.97
}
}
},
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 129.38,
“partnerNetPrice“: 106.10
}
}
}
],
“totalPrice”: {
“price”: {
“recommendedRetailPrice”: 202.51,
“partnerNetPrice”: 166.07,
“bookingFee”: 10.79,
“partnerTotalPrice”: 176.86
}
}
}
Example response (commission model)
{
“bookingRef”: “BR-872448818”,
“bookingHoldInfo”: {
“availability”: {
“status”: “HOLDING”,
“validUntil”: “2022-04-13T13:07:34Z”
},
“pricing”: {
“status”: “HOLDING”,
“validUntil”: “2022-04-13T13:07:33.620645Z”
}
},
“currency”: “EUR”,
“lineItems”: [
{
“ageBand”: “CHILD”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 73.13,
“partnerNetPrice”: 59.97
}
}
},
{
“ageBand”: “ADULT”,
“numberOfTravelers”: 1,
“subtotalPrice”: {
“price”: {
“recommendedRetailPrice”: 129.38,
“partnerNetPrice“: 106.10
}
}
}
],
“totalPrice”: {
“price”: {
“recommendedRetailPrice”: 202.51,
“partnerNetPrice”: 166.07,
“bookingFee”: 0,
“commission”: 20.25,
“partnerTotalPrice”: 174.37
}
}
}
Invoicing
If you are a merchant API partner with the markup model, Viator will invoice you the amount returned under the partnerTotalPrice in the /bookings/book response in the currency sent in the booking request. It’s possible to make a booking in one of the following currencies: AUD, CAD, EUR, GBP, USD.
If you make multiple bookings using different currencies, you will receive separate invoices from Viator for each currency. If you would prefer to receive only one invoice, please make sure to specify the same currency in all your booking requests (this is recommended).
If you attempt to use a non-supported currency, you will receive this error message:
Example error message
{
“code”: “BAD_REQUEST”,
“message”: “Incorrect currency code provided”,
“timestamp”: “2021-08-06T14:57:44.478266Z”,
“trackingId”: “5C28A86F:2ECE_0A5D03D4:01BB_610D4DE8_6A78A4:1A92”
}
In case the booking needs to be amended and the change would result in a different price, the original booking needs to be canceled using the API and a new booking needs to be made. Viator will not invoice you for any canceled bookings as long as they have been canceled within the free cancellation window. This can be verified with the /bookings/{booking-reference}/cancel-quote endpoint (read more about the Viator cancellation policies and processes in this article).
For example, if you received the following response from the /bookings/{booking-reference}/cancel-quote endpoint, Viator would invoice you 50% of the booking amount if you were to cancel:
Example response
{
“bookingId”: “BR-585389372”,
“refundDetails”: {
“itemPrice”: 12148.54,
“refundAmount”: 6074.27,
“refundPercentage”: 50.00,
“currencyCode”: “GBP”
},
“status”: “CANCELLABLE”
}
It’s recommended to store the logs with responses to the /bookings/{booking-reference}/cancel-quote and /bookings/{booking-reference}/cancel endpoints for canceled bookings for at least a month so that they can be used to dispute any invoicing discrepancies. If you’d like to open a dispute regarding your Viator invoice, please fill in this form.
Please note:
-
You should not rely on the pricing returned from any of the availability schedule endpoints for invoicing, as this data is cached. To ensure accurate pricing, it’s important to perform a real-time check using the /availability/check endpoint before confirming the booking. If you use the hold endpoint to secure a price before the customer confirms the booking, make sure to verify the timestamp in the response, as it indicates how long the price will be held. If the booking request is not submitted within the specified time frame, the price may have changed. Following these steps is crucial to ensure the pricing is correct and to avoid discrepancies between the expected and invoiced amounts.
Extra charges
Some products come with extra charges that must be paid directly to the tour operator at the destination. These additional charges are not included in the price charged at the time the booking is confirmed.
Online travel agencies that must comply with the regulations imposed by California Legislation SB-478 are required to display the full product charges, excluding taxes. To ensure compliance, the “full price” must be displayed throughout the entire purchasing journey, including all fees.
Viator requests information about these additional charges from suppliers and shares it via the API to help our partners provide this information to their customers. If this legislation applies to your customer’s location, you can use the relevant API fields to convey all applicable fees and charges. Examples of additional charges include: admission charges, government fees, public transportation, and meals.
Disclaimer: Viator provides all relevant information through the API, but it is the partner’s responsibility to ensure full compliance with the rules and regulations applicable to their business. Prices payable to third parties are provided to us by the operator, and may be subject to change
The Viator API returns extra charges at 3 levels:
1. Product endpoints, to help you display exclusions applicable to each product based on the product content response:
Extra charges can be found under “exclusions” and they are grouped by category (eg. “FEES_AND_TAXES”) and type (eg. “ADMISSION_CHARGE”). The typeDescription field contains the name of the extra charge in natural language, making it suitable for display to users. Suppliers may also provide supplementary details about the charge, which are returned as free text (description) and can be displayed on the front end to provide further information to customers. This content is translated into all languages supported in the API.
Response examples
Example for an Admission charge response |
Example for an Excess charges type response |
“exclusions”: [
{
“category”: “CHARGESS_AND_TAXES”,
“categoryDescription”: “Charges”,
“type”: “ADMISSION_CHARGE”,
“typeDescription”: “Admission Charge”,
}
|
“exclusions”: [
{
“category”: “EXCESS_CHARGES”,
“categoryDescription”: “Excess charges”,
“type”: “EXCESS_BAGGAGE”,
“typeDescription”: “Excess baggage”,
}
|
All inclusions and exclusions grouped by category and type are listed here. Please keep in mind that this list is subject to change.
2. Upper funnel endpoints, to help you display additional charges information on upper funnel pages (before a passenger mix is applied).
- /schedules/modified-since
- /availability/schedules/bulk
- /availability/schedules/{product-code}
- /products/search
- /search/freetext
The pricing.extraChargesSummary object returns the following fields with extra charges: fromPrice, fromPriceBeforeDiscount and extraCharges.
Field definitions
Field name | Description |
extraChargesSummary | Information about the lowest price with extra charges available for this product. |
extraChargesSummary.fromPrice |
fromPrice value including max extra charges value to be paid in destination by the traveler.
This value will only be returned if the product has extra charges in at least one bookableItem. |
extraChargesSummary.fromPriceBeforeDiscount |
If the product is presently discounted, this field shows what the value of fromPricePlusExtraCharges would be if no discount had been applied; otherwise, it will be absent.
This value will only be returned if the product has extra charges in at least one bookableItem. |
extraChargesSummary.extraCharges |
The highest amount that a traveler could be asked to pay in-destination based on their age, day of the week, time of the year or any other criteria defined by the supplier for the bookableItem used to calculate the starting price.
|
Response examples
/products/search /search/freetext |
/availability/schedules/{product-code} /availability/schedules/bulk /schedules/modified-since |
“pricing”: {
“summary”: {
“extraChargesSummary”: {
“fromPrice”: 460,
“fromPriceBeforeDiscount”: 510,
“extraCharges”: 20
}
|
“summary”: {
“extraChargesSummary”: {
“fromPrice”: 460,
“fromPriceBeforeDiscount”: 510,
“extraCharges”: 20
}
|
3. Lower funnel endpoints, to help you display the accurate extra charges for the selected pax mix and travel date to customers on the checkout page.
Field definitions
Field name | Description |
extraChargesSummary | Information about the extra charges applicable to this bookableItem. Note: Prices payable to third parties are provided to us by the operator, and may be subject to change |
extraChargesSummary.price |
|
extraChargesSummary.price.recommendedRetailPrice | The recommended retail price value including max extra charges value to be paid in destination by the traveler. This value will only be returned if the bookableItem passed in the request has extra charges. |
extraChargesSummary.priceBeforeDiscount
|
|
extraChargesSummary.priceBeforeDiscount.recommendedRetail
|
Non-discounted price if price has a discount applied to it. It shows what the value of recommendedRetailPricePlusExtraCharges would be if no discount had been applied; otherwise, it will be absent. |
extraChargesSummary.mandatory | Information about the mandatory Extra Charges applicable to this bookableItem. |
extraChargesSummary.mandatory.totalExtraCharges
|
Total amount of extra charges considering bookableItem and paxMix. |
extraChargeSummary.mandatory.Items
|
List of all extra charges that apply to the bookableItem. Can be used to build a breakdown list of costs. Each item corresponds to a product Exclusion that requires extra charges to be paid. |
extraChargesSummary.mandatory.Items.name | Extra charges description. |
extraChargesSummary.mandatory.Items.amountPerUnit | The amount per unique extra charges. |
extraChargesSummary.mandatory.Items.numberOfUnits*
|
How many times the extra charges apply. If the Eextra charges value is to be charged per person this value will match numberOfTravelers passed in the request. If the extra charges value is to be charged per unit this value will match the amount of groups/units in the request. |
extraChargesSummary.mandatory.Items.totalAmount | Total amount of all extra charges for a given item. |
extraChargesSummary.mandatory.inDestination | The extra charges amount in destination currency (if different from request currency). |
extraChargesSummary.mandatory.inDestination.amountPerUnit | The cost per one extra charges in destination currency. Note: Prices payable to third parties are subject to change due to exchange rates fluctuations between the request time and the travelDate. |
extraChargesSummary.mandatory.inDestination.totalAmount | Total amount of all extra charges in destination currency Note: Prices payable to third parties are subject to change due to exchange rates fluctuations between the request time and the travelDate. |
extraChargesSummary.mandatory.inDestination.currency | The supplier preferred currency to be paid in destination. |
translationInfo | Information about whether the text in this response was machine-translated. |
translationInfo.containsMachineTranslatedText | Indicates whether this product description utilizes text in any of its natural language fields that was automatically machine-translated with no human oversight. |
translationInfo.translationSource |
One of: “MACHINE” – The text provided by the supplier is in a different language and has been automatically translated by our systems with no human oversight. “ORIGINAL” – The text provided by the supplier is in the language that is standard for their locale. “MANUAL” – The text provided by the supplier was in a different language to the standard for their locale; however, whether this is a direct translation of the original text (performed either by machine or human) or whether it is a customised description for speakers of this language is not known. |
translationInfo.translationAttribution | Value specifying the machine-translation service vendor. At present, translation attribution is not a requirement. Example: “GOOGLE”. |
/cart/hold endpoint only | |
extraChargesSummary
|
Total amount of extra charges considering all cart bookable items. |
extraChargesSummary.price.recommendedRetailPrice | Total RRP including extra charges for all cart bookable items. |
extraChargesSummary.priceBeforeDiscount.recommendedRetailPrice | Total RRP including extra charges for all cart bookable items if no discount had been applied. |
Response examples
/availability/check | /bookings/hold | /bookings/cart/hold |
“bookableItems”: “totalPrice”: “extraChargesSummary”: “price”:
“recommendedRetailPrice“: 559.52
“priceBeforeDiscount”:
“recommendedRetailPrice”: 579.52
“mandatory”: “totalExtraCharges”: 26.3,
items: “name”: “Museum entrance Charge”,
“numberOfUnits”: 2,
“amountPerUnit”: 13.15,
“totalAmount”: 26.3
“inDestination”
“amountPerUnit”: 30,
“totalAmount”: 30,
“currency”: “SGD”
[…
]
“translationInfo”:
“containsMachineTranslatedText“: true,
“translationSource”: “MACHINE”,
“translationAttribution“: “GOOGLE“
|
“totalPrice”: “extraChargesSummary”: “price”:
“recommendedRetailPrice“: 559.52
“priceBeforeDiscount”:
“recommendedRetailPrice”: 579.52
“mandatory”: “totalExtraCharges”: 26.3,
items: “name”: “Museum entrance Charge”,
“numberOfUnits”: 2,
“amountPerUnit”: 13.15,
“totalAmount”: 26.3
“inDestination”
“amountPerUnit”: 30,
“totalAmount”: 30,
“currency”: “SGD”
“translationInfo”:
“containsMachineTranslatedText“: true,
“translationSource”: “MACHINE”,
“translationAttribution“: “GOOGLE“
|
“items”: “extraChargesSummary”: “price”:
“recommendedRetailPrice“: 559.52
“priceBeforeDiscount”:
“recommendedRetailPrice”: 579.52
“mandatory”: “totalExtraCharges”: 26.3,
items: “name”: “Museum entrance Charge”,
“numberOfUnits”: 2,
“amountPerUnit”: 13.15,
“totalAmount”: 26.3
“inDestination”
“amountPerUnit”: 30,
“totalAmount”: 30,
“currency”: “SGD”
“extraChargesSummary”: “price”:
“recommendedRetailPrice“: 559.52
“priceBeforeDiscount”:
“recommendedRetailPrice”: 579.52
“totalExtraCharges”: 20
“translationInfo”:
“containsMachineTranslatedText“: true,
“translationSource”: “MACHINE”,
“translationAttribution“: “GOOGLE“
|
*Please note: the number of units is calculated differently for products with different pricing types:
- “PER_PERSON”: The number of units equals the number of travelers.
- “UNIT”: The number of units equals the number of units (groups), regardless of the number of travelers in each unit. Currently, it is only possible to book for a single unit, so the number of units in this case is always 1.
Maximum extra charges vs. actual fees in destination
The extra charges returned in the API represent the maximum fees that a customer may incur at the destination.
For instance, if the maximum extra charge is $10 per person and the booking is for 2 adults and 3 children, the total maximum extra charge would be $50 (5 x $10). In practice, some charges may not apply to certain individuals, such as children, and the actual fees paid may be lower. For example, the attraction may not charge extra for children, reducing the total extra fees to $20 instead of the maximum $50.
Please be aware that these fees are subject to change, and the information provided reflects the details available at the time of booking. Factors such as currency exchange rates may affect the final amount the traveler pays at the destination.
Sharing this information with users helps set accurate expectations and minimize any surprises during their trip.