Viator API Documentation & Specification – Merchant Partners

Description

<style type=‘text/css’> code { white-space: nowrap; } a { font-weight: bold; }

figure { width: 100%; text-align: center; font-style: italic; font-size: smaller; text-indent: 0; border: thin silver solid; margin: 0.5em; padding: 0.5em; }

</style>

Updates

Latest update:

DateDescription
3 Feb 2021Added Special offers and on-sale pricing section
28 Oct 2020Updated FAQ section re booking questions, traveler names, and pricing
16 Sep 2020Modified FAQ section re booking currencies, supplier name display and requesting additional reviews
20 July 2020Added Booking references section

Previous updates: See Update log

Overview

The Viator Partner API comprises a set of endpoints that can support the operation of a fully-featured tours and experiences booking website or application; or, it can be integrated with your existing travel-booking software.

The API exposes a variety of services that allow the retrieval of all product details, such as descriptions, pricing, terms and conditions, photos and reviews. This data can either be ingested periodically and managed on your local system, or calls can be made in real time to retrieve content in response to your users’ activity on your systems.

The API allows product availability schedules to be retrieved in bulk or queried in real-time, and it can perform pricing calculations according to the number and type of traveler for the wide variety of product option combinations typically available in the tours and activities sales workflow.

The API provides booking and post-booking functionality, allowing booking requests, ticket purchase, and booking status updates.

Various utility services are available to map between yours and Viator’s data taxonomy.

Please note: The API does not provide services for storing data, such as user accounts. We assume that merchant partners have their own systems for storing this data.

Who is the API for?

The Viator Partner API is designed for use by organizations and individuals partnered with Viator in one of the following capacities:

Merchant partners

A merchant partner is one who operates as the merchant of record; i.e., takes full responsibility for all monetary transactions carried out by their users, as well as providing customer support with regard to providing help, processing cancellations and refunds, and liaising between suppliers and customers when the need to communicate information arises.

Merchant partners are invoiced periodically by Viator for all product sales. You will need to demonstrate that you have access to the appropriate infrastructure to effectively support the requisite business operations in order to become a merchant partner.

Viator Branded Affiliates (VBAs)

VBAs have full access to the areas of the API relating to content, but sales of Viator products must be carried out on the Viator site itself; therefore, access to the booking or transactional endpoints necessary to operate as the merchant of record (i.e., merchant partners) is restricted.

When a customer wishes to book a product from a VBA partner’s site, they are instead redirected to viator.com in order to complete the purchase; whereas, merchant partners are able to process and manage bookings through the Viator API itself, allowing their customers to book products without leaving the partner’s site.

Viator affiliates instead generate unique URLs that redirect their users to the Viator site, resulting in a cookie being set such that all transactions will accrue a commission for that partner until the cookie expires.

Purchases of products originating from the VBAs site are recorded and a commission on these sales is paid periodically.

VBAs with booking capability

VBAs also have the option of allowing their customers to process bookings directly from their site and via the API – similar to a merchant partner – without being redirected to viator.com to complete their transaction. This partner type sends customer details, product details and credit card payment information via the API, but Viator retains control of and responsibility for processing payments and customer support.

White label partners

White label partners do not operate their own site infrastructure. Instead, Viator provides a white label site with full functionality that can be branded according to the partner’s wishes.

Uses of the Viator Partner API

The Viator Partner API is used to carry out the following tasks:

Product search and ingestion

Partners can use the product search endpoints to retrieve lists of products from Viator’s inventory relevant to their business. The available search criteria include:

  • The location (destination) in which the product operates
  • Whether the product is associated with a well-known tourist attraction; e.g., Empire State Building
  • The type of product (known as its category and/or subcategory)
  • The time period during which the product operates
  • Words or phrases that occur in a product’s description via a free-text search

Partners who prefer to download product details periodically (instead of performing all operations in real time in response to user behavior) do so by using the product search endpoints to compile a list of products that they wish to sell on their site. They then download comprehensive product details for each via the /product endpoint.

Product search endpoints:

EndpointUse
/search/productsAllows searching for products according to: destination / location, relationship to a known tourist attraction; category and/or subcategory; date of operation
/search/products/codesRetrieves product details for products that match a list of product codes (unique identifiers for the product)
/search/freetextRetrieves product details for products that include the search terms in the product’s description and details.
/available/productsRetrieves products that are identified by specific product codes, operate during a specified day range and accept a certain number of adult travelers

Product information endpoints:

All information about a product that must be communicated to customers prior to purchase is available via /product and its auxiliary endpoints. This content is generally used to construct product display pages and for performing local searches.

Important information about a product includes:

  • Product and supplier names
  • Geographic location
  • Product description
  • Category and subcategory
  • Photos (from both users and the supplier)
  • User reviews and ratings
  • Product options (variants of the tour/activity, such as starting times, passenger mix options, and inclusions/add-ons, including basic pricing information for each)
  • Which age ranges can participate
  • Booking details
  • Cancellation policies
  • Basic pricing
  • Logistics
    • Inclusions (e.g., provided meals)
    • Exclusions (e.g., entrance fees to visited attractions)
    • Health restrictions and accessibility
    • Departure times
    • Passenger pick-up
    • Duration
    • Tour routes

Availability

The availability of a tour is communicated via the API’s availability endpoints. The availability aspects of a product include:

  • On which days and at which times the product is available to be booked
  • Whether the product option (variant) supports a certain combination of passengers according to age and number
  • Pricing information

Some partners choose to bulk-ingest availability information for their products in order to expedite this part of the customer workflow or to facilitate a local search functionality on their website; but, because this information changes very regularly, a final real-time call is generally recommended to ensure that when the booking request is submitted by the customer it is unlikely to fail on account of a change in availability.

Availability endpoints

EndpointUse
/booking/availabilityReturns the product option with the lowest price that is available on each day
/booking/availability/datesReturns all available dates for a product (but without regard to product option)
/booking/availability/tourgradesReturns all product options for a product that are available on the specified day for the specified passenger mix
/booking/availability/tourgrades/pricingmatrixReturns a detailed matrix of product options, passenger mixes and the pricing applicable to each combination
/booking/calculatepriceProvides a reconfirmation of a product’s availability with respect to the product option and passenger mix provided and calculates a final price; used as a final availability check immediately prior to making a booking

Booking and cancellations

Merchant partners and VBAs with booking capabilities can use the Viator Partner API to purchase the product through the /booking/book endpoint.

The API also provides services to:

  • Enquire about the status of an existing booking
  • Retrieve tickets/vouchers for the product
  • Cancel a booking

Booking endpoints

EndpointUse
/booking/bookMake a booking / purchase a product
/booking/statusRetrieve multiple detailed booking statuses based on a range of specified criteria
/booking/status/itemsSimilar to /booking/status, but provides slightly less detail and can be called more frequently

Cancellation endpoints

EndpointUse
/bookings/{booking-reference}/cancel-quoteReturns the expected outcome of a booking cancellation request (taking into consideration the product’s cancellation policy) were the cancellation request performed immediately
/bookings/{booking-reference}/cancelCancels the booking and assigns a refund depending on the product’s cancellation policy

Auxiliary services

Taxonomical data sets are required to interact meaningfully with the Viator Partner API; for example, mappings from destination (location of operation) to their respective identification codes. This information may occasionally change or be added to. Consequently, the API includes endpoints that return the most up-to-date versions of this information.

Taxonomy endpoints

EndpointUse
/taxonomy/destinationsRetrieves a list of destination names, types and unique identifiers to be used when interacting with the Viator Partner API
/taxonomy/categoriesRetrieves a list of product categories for a destination that can be used as a means of filtering when searching for products using the /search/products endpoint
/taxonomy/attractionsRetrieves a list of tourist attractions (e.g., the Eiffel Tower or Empire State Building) and their associated identification codes to be used as a means of searching for available products; for example, in the /search/products service
/booking/hotelsRetrieves a list of hotels, including names and geographic locations, to be used when making booking requests

Authentication

Note:

  • The authentication mechanism for this API has been updated recently. Now, partners can also authenticate using a new style of API key that is included in each call as a <u>header parameter</u>. Previously, authentication was accomplished by including an API key as a query parameter.

  • Partners who are currently authenticating via the API key query parameter can continue to authenticate in this way; however, access to the new booking cancellation endpoints (/bookings/cancel-reasons, /bookings/cancel-quote and /bookings/cancel) does require the new-style of API key. All other endpoints remain compatible with both authentication methods.

  • If you would like to switch to the new style of key, please speak to your business development account manager.

API key

Access to the API is managed using an API key that is included as a header parameter to every call made to all API endpoints described in this document.

Header parameter nameExample value
exp-api-keybcac8986-4c33-4fa0-ad3f-75409487026c

If you do not know the API key for your organization, please contact your business development account manager for these details.

Please note that language localization is now controlled on a per-call basis. Previously, language localization was controlled via API-key configuration, with one language available per API key. Under the present scheme, you can access any language enabled for your organization’s point of sale via a single API key.

Language selection is accomplished by specifying the desired language as a header parameter (Accept-Language). See Accept-Language header for available language codes. If you would like access to additional languages, please contact your business development account manager.

Legacy API key

Previously, authenticating to this API was accomplished by passing an API-key as a query parameter appended to the URI for each call; e.g.:

GET https://viatorapi.sandbox.viator.com/service/taxonomy/destinations?apiKey=xxxxxxxxxxxxxxxxxx

This method of authentication remains available for backwards-compatibility with existing implementations. If you would like to upgrade to the new style of API key, please contact your business development account manager.

Key concepts

Content ingestion and caching strategy

Much of the information you will need to retrieve from the Viator API – such as the taxonomy, product lists and product details – do not change frequently.

Therefore, we recommend implementing a caching strategy in order to eliminate unnecessary traffic to Viator’s servers and improve the operation of your site.

This section discusses the different strategies for retrieving and caching Viator’s product catalogue.

You will need to decide on how you will retrieve and manage content from Viator’s product catalogue. The two main options are as follows:

1. API response caching

Partners retrieve content as-needed and cache responses on a service-by-service basis

If you do not need to store product details locally, we recommend performing caching of on a service-by-service basis; i.e., storing the entire response and applying a time-to-live (TTL) of less than 24 hours.

Benefits of API response caching

  • All the benefits of caching with minimal overhead
  • Minimal risk of serving stale or invalid data cached on the partner’s side
  • No need to download data about products that are not selling
  • A smaller volume of local data improves cache hit performance
  • Fewer requests made of Viator’s systems
  • Avoids rate limitations
  • Closer adherence to best practices
  • Removes need to manage a complex data structure locally

Service endpoints to cache

Caching should only be applied to services that yield infrequently changing data; i.e.:

Note: these services should be considered cacheable even though some are POST and none include a Cache-Control HTTP header in their response.

2. Periodic content ingestion

Partners download either the full product catalogue or a subset of the catalogue at regular intervals based on destination, linked attraction, or product category filters.

Who should use periodic ingestion

This approach may be preferable for partners whose requirements include:

  • System agnosticism/data centralization – i.e., partners who are simultaneously selling products from vendors other than Viator, have existing product databases or are likely to want to maintain a central product catalogue with a unified taxonomy / data structure
  • Enhanced search capability – i.e., the ability to apply different categorization rules, filters, exclusions or search optimizations to the product catalogue; e.g., grouping or filtering products according to criteria other than those supported directly by the Viator API (destination, attraction-link or category)

Frequency of content ingestion

We recommend that you perform an ingestion of the product catalogue once every 24 hours.

How to retrieve product codes

Make a call to one of the product search services:

  • /search/products – to search by destId (destination), catId (category), subCatId (subcategory) or seoId (attraction)
  • /search/freetext – free-text search across all identifying fields

How to retrieve all products in the catalogue

To retrieve all products from the Viator catalogue:

  • Retrieve all available destination identifiers (destId) from the /taxonomy/destinations service
  • Iterate through the complete list of destIds you retrieved in the previous step, and call /search/products for each destId

Note: As some products operate in multiple destinations, the same product code may be returned for a range of different destinations. Therefore, make sure your list of product codes only contains one copy of each code.

You may then iterate through this list of product codes to retrieve any other product details necessary in order to properly populate your local database with the information you require.

Retrieving a subsection of the product catalogue

You may wish to retrieve only some of the products available in the Viator catalogue; for example, if your organization is only interested in selling products that operate locally.

Your top level search using /search/products is restricted to one of the three main categorization methods for products; i.e., destination, category/subcategory, or attraction-link; however, you may employ your own methods to filter the selection of products based on any attribute in the product data structure.

Dealing with pagination using totalCount and topX

Due to the large number of results that can be returned by the /search/products service, the request might exceed the 30-second time-out limitation on both sandbox and live servers. Therefore, you will need to make multiple requests to this service including pagination information in order to retrieve all products that match your search criteria.

This is accomplished by sequentially requesting successive segments of the results using the topX request parameter together with the totalCount response field; i.e.:

  • For your first request, specify a topX of "1-100"
    • Note: this range is inclusive; i.e., "topX": 1-100" will yield the first 100 records
  • The first response will indicate the total number of records available through the value of the totalCount field in the response object; e.g.: "totalCount": 13843
  • For each subsequent request, specify the next logical ‘chunk’ of data via the topX parameter of the request; e.g.:
    • “topX”: “1-100”
    • “topX”: “101-200”
    • “topX”: “13801-13843”

Rate limiting

Due to the heavy load that pre-caching can place on Viator’s servers and the downstream servers we connect to, we apply a rate limit of 150 requests per 10 second time window.

Request rates exceeding this limit will result in a HTTP 429 (Too Many Requests) status code being returned.

Note: The rate is calculated over a rolling 10-second time window

  • In order to avoid running-up against rate limits:
    • insert a delay of 2s if you receive a HTTP 429 status code
    • do not run this as a multi-threaded process

Categorization of content

The products available in Viator’s catalogue are mainly categorized according to:

  1. Destination: every product in the Viator catalogue is categorized according to the destination/locale in which it operates. There are three kinds of destination: <table> <thead> <th>Destination type</th> <th>Meaning</th> </thead> <tbody> <tr> <td>“COUNTRY”</td> <td>A country; e.g., “Australia”, “Japan”, “USA”</td> </tr> <tr> <td>“REGION”</td> <td>A geographical region or state; e.g., “South Australia”, “French Riviera”, “Punjab”</td> </tr> <tr> <td>“CITY”</td> <td>A city within a state; e.g., “Townsville”, “Osaka”, “Singapore”</td> </tr> </tbody> </table> <table> <thead> <tr> <th><code>destinationName</code></th> <th><code>destId</code></th> <th><code>destinationType</code></th> </tr> </thead> <tbody> <tr> <td>USA</td> <td>77</td> <td>COUNTRY</td> </tr> <tr> <td>Wisconsin</td> <td>22231</td> <td>REGION</td> </tr> <tr> <td>Madison</td> <td>24146</td> <td>CITY</td> </tr> <tr> <td>France</td> <td>51</td> <td>COUNTRY</td> </tr> <tr> <td>Brittany</td> <td>21942</td> <td>REGION</td> </tr> <tr> <td>Rennes</td> <td>21943</td> <td>CITY</td> </tr> </tbody> </table>

  2. Category and subcategory: the products in the Viator catalogue are grouped according to the kind of activity they entail and may be subcategorized further to provide greater specificity; for example: <table> <thead> <tr> <th>Category</th> <th>Subcategories</th> </tr> </thead> <tbody> <tr> <td rowspan=3>Air, Helicopter & Balloon Tours</td> <td>Air Tours</td> </tr> <tr> <td>Helicopter Tours</td> </tr> <tr> <td>Balloon Rides</td> </tr> <tr> <td rowspan=2>Weddings & Honeymoons</td> <td>Wedding Packages</td> </tr> <tr> <td>Honeymoon Packages</td> </tr> </tbody> </table>

  3. Attraction link (i.e., association to a particular “point of interest”); e.g.: <table> <thead> <tr> <th>Attraction</th> <th>seoId</th> <tr> </thead> <tbody> <tr> <td>Bellagio Fountains</td> <td>1243</td> </tr> <tr> <td>Black Canyon</td> <td>4437</td> </tr> <tr> <td>Epcot Centre</td> <td>1141</td> </tr> </tbody> </table>

Booking concepts

Booking types - on-request and freesale

Bookings made with Viator can be either freesale (immediate confirmation) or on-request, which require us to confirm with our product supplier that the product has not sold out and is still available. This difference must be clearly communicated to the customer during the price check and on the order summary post-purchase page.

For freesale bookings, the voucher becomes available immediately, and the customer’s credit card will be charged at the time of booking. For on-request bookings, confirmation will be sent to the customer within a timeframe supplied in the /booking/calculateprice and /booking service responses.

The customer’s credit card will be charged once their on-request booking is confirmed.

bookingEngineId

bookingEngineId is a field returned in the responses from several endpoints documented in this manual. It is a booking type specifier indicating whether, when the product in question is booked, the booking will be CONFIRMED immediately or if it will remain PENDING even after the booking has been made, indicating that it is an on-request product.

bookingEngineId takes one of the following values:

  • "FreesaleBE" – the product will be confirmed immediately and the supplier will be sent a notification.

  • "UnconditionalBE" - the product will be confirmed immediately and the supplier will not be notified.

  • "DeferredCRMBE" - the product is an on-request product and the booking will not be confirmed immediately. The booking will remain with a PENDING status after it is made, to be confirmed by the supplier within the time specified in the hoursConfirmed field available in the booking response and post-booking services.

  • "FreesaleOnRequestBE" - The product is freesale up until a certain number of days before the travel date, after which it becomes on-request. It is then referred to as being within the on-request period. If a booking is made within the on-request period, the product can be considered to be an on-request product. Once the booking has been made, the bookingEngineId will change to either "FreesaleOnRequestBE:OnRequest" or "FreesaleOnRequestBE:Freesold" depending on the travel date and the on-request period.

Tour grades

Products can have one or more tour grades. Each tour grade might represent a departure time or different tour option, such as additional meals, transport and so forth. If the tour grade code is "DEFAULT", do not display this to the customer, simply hide the product’s tour grade information.

Language options

Many tours deliver a commentary in multiple languages using multilingual tour guides or with written or prerecorded information. Where available, the customer can preselect their preferred language option.

Traveler mix (pax)

Some tour grades have defined traveler mixes used to price family passes; or, they might have special mixes for limited passenger tours, such as small buggies or weddings.

These traveler mixes are provided by the /booking/availability/tourgrades service. You may need to display these to your customers so that they are able to understand why they can or cannot select a particular tour grade if there is a traveler mix mismatch.

Pick-up location and hotel lists

Some products have pick-up and return shuttle bus services. For these tours, you will need the customer to supply a pick-up hotel, or they must select live locally or hotel not yet booked options.

Viator maintains pick-up hotel lists for many popular destinations. These lists are available for customers to select their pick-up location for various tours. For destinations without hotel lists, customers can enter the name of their hotel. If a customer’s hotel is not listed, they should be able to enter a hotel name; however, pick-up may not be possible for that hotel.

Lead traveler

Each tour booking requires a lead traveler to be identified. To identify the lead traveler in your request, set the leadTraveller flag to true in the traveler class.

Booking questions

Some products have a list of one or more booking questions that need to be asked. Some are mandatory. The question, a description, etc are provided in the product details object. The answers need to be included with the booking request.

SSL/HTTPS

Calls to the /booking/book service must use a secure channel (https) as they contain credit card information.

Promo codes

Viator can create promotional (promo) codes for discounts and other purposes. As it’s unlikely for you to wish to support this feature, we recommend supplying null in the promoCode field and not including any customer-entered fields during the checkout process.

Partner data

Partners can also supply additional information for their own internal purposes. These are attached to booking reports and other materials for use in allocating commissions to agents and so forth.

Availability services

Product availability information can be retrieved with the following services:

Example: multiple departures in a single day

Multiple departures in a single day (each represented by a tour grade) and the language options (langServices).

This request is for 3 adults on a helicopter tour:

  • Note: No prices are returned if the tour grade is unavailable.

Request object (/booking/availability/tourgrades):

{
  "productCode": "2280AAHT",
  "bookingDate": "2013-05-11",
  "currencyCode": "EUR",
  "ageBands": [{
    "bandId": 1,
    "count": 3
  }]
}

Response object (/booking/availability/tourgrades) :

{
  "data": [{
    "available": false,
    "ageBands": null,
    "langServices": null,
    "gradeCode": "EARLYM",
    "unavailableReason": "BOOKING_CUTOFF_EXPIRED",
    "gradeTitle": "Early Morning Departure",
    "gradeDepartureTime": "",
    "gradeDescription": "Flight departs Las Vegas between 7am &amp; 8am",
    "defaultLanguageCode": "en",
    "ageBandsRequired": null,
    "currencyCode": "ERROR",
    "retailPrice": 0,
    "bookingDate": "2013-05-11",
    "retailPriceFormatted": "",
    "merchantNetPrice": 0,
    "merchantNetPriceFormatted": "",
    "sortOrder": 1
  },
  {
    "available": false,
    "ageBands": null,
    "langServices": null,
    "gradeCode": "LATEM",
    "unavailableReason": "BOOKING_CUTOFF_EXPIRED",
    "gradeTitle": "Late Morning Departure",
    "gradeDepartureTime": "",
    "gradeDescription": "Flight departs Las Vegas between 9:45am &amp; 10:45am",
    "defaultLanguageCode": "en",
    "ageBandsRequired": null,
    "currencyCode": "ERROR",
    "retailPrice": 0,
    "bookingDate": "2013-05-11",
    "retailPriceFormatted": "",
    "merchantNetPrice": 0,
    "merchantNetPriceFormatted": "",
    "sortOrder": 2
  },
  {
    "available": false,
    "ageBands": null,
    "langServices": null,
    "gradeCode": "EARLYA",
    "unavailableReason": "BOOKING_CUTOFF_EXPIRED",
    "gradeTitle": "Early Afternoon Departure",
    "gradeDepartureTime": "2:50 PM",
    "gradeDescription": "Flight departs Las Vegas between 12:30pm &amp; 1:30pm",
    "defaultLanguageCode": "en",
    "ageBandsRequired": null,
    "currencyCode": "ERROR",
    "retailPrice": 0,
    "bookingDate": "2013-05-11",
    "retailPriceFormatted": "",
    "merchantNetPrice": 0,
    "merchantNetPriceFormatted": "",
    "sortOrder": 3
  },
  {
    "available": false,
    "ageBands": null,
    "langServices": null,
    "gradeCode": "LATEA",
    "unavailableReason": "BOOKING_CUTOFF_EXPIRED",
    "gradeTitle": "Late Afternoon Departure",
    "gradeDepartureTime": "",
    "gradeDescription": "Flight departs Las Vegas between 3:15pm &amp; 4:15pm; available Ap",
    "defaultLanguageCode": "en",
    "ageBandsRequired": null,
    "currencyCode": "ERROR",
    "retailPrice": 0,
    "bookingDate": "2013-05-11",
    "retailPriceFormatted": "",
    "merchantNetPrice": 0,
    "merchantNetPriceFormatted": "",
    "sortOrder": 4
  }],
  "vmid": "221001",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-06-04T17:01:34+0000",
  "totalCount": 1,
  "errorReference": null,
  "errorMessageText": null,
  "success": true,
  "errorName": null
}

Example: traveler mix mismatch

The request is for five adults, but this product only support up to four adults.

Example request object (/booking/availability/tourgrades):

{
  "productCode": "2280ULTWED",
  "bookingDate": "2013-12-11",
  "currencyCode": "EUR",
  "ageBands": [{
    "bandId": 1,
    "count": 5
  }]
}

Example response object The response contains "TRAVELLER_MISMATCH" and you can see the ageBandsRequired values for the adult (1) age band in the available tour grade.

{
  "data": [{
    "available": false,
    "ageBands": null,
    "langServices": null,
    "gradeCode": "DEFAULT",
    "unavailableReason": "TRAVELLER_MISMATCH",
    "gradeTitle": "DEFAULT",
    "gradeDepartureTime": "12:00 AM",
    "gradeDescription": "DEFAULT",
    "defaultLanguageCode": "en",
    "ageBandsRequired": [
    [{
      "bandId": 1,
      "minimumCountRequired": 2,
      "maximumCountRequired": 2
    }],
    [{
      "bandId": 1,
      "minimumCountRequired": 3,
      "maximumCountRequired": 3
    }],
    [{
      "bandId": 1,
      "minimumCountRequired": 4,
      "maximumCountRequired": 4
    }]],
    "currencyCode": "ERROR",
    "retailPrice": 0,
    "bookingDate": "2013-12-11",
    "retailPriceFormatted": "",
    "merchantNetPrice": 0,
    "merchantNetPriceFormatted": "",
    "sortOrder": 1
  }],
  "vmid": "221001",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-06-04T17:02:35+0000",
  "totalCount": 1,
  "errorReference": null,
  "errorMessageText": null,
  "success": true,
  "errorName": null
}

Understanding the pricingUnit field

This section explains the meaning and function of the pricingUnit field in the response object received from the /booking/availability/tourgrades/pricingmatrix service.

Request body

The /booking/availability/tourgrades/pricingmatrix service takes the following parameters as input in its request body:

ParameterTypeMeaning
productCodestringunique alphanumeric identifier of the product to enquire about; e.g., 10040WORLD
monthstringmonth of the year by which to filter results
yearstringyear by which to filter results
currencyCodestringcurrency code for the currency in which to display pricing information

Example request body

Sending the following request body to the /booking/availability/tourgrades/pricingmatrix service will retrieve pricing information for “Skip the Line: World of Discoveries Entrance Ticket in Porto” (product code: 10040WORLD).

{
  "productCode": "10040WORLD",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}

Response object

Within each object item of the tourGrades array – each of which gives the pricing details for a specific tour grade – is a pricingMatrix array. Each object in this array details the per-age-band pricing for a specific pricing unit (pricingUnit) associated with that product.

Using this information, you should be able to calculate the total cost of the booking – considering any booking options – with regard to the number of participants.

How to identify the fundamental unit prices for a booking, which are then summed in order to calculate a total price, is detailed below.

Note that in the response object received from the service, pricing schedules are organized hierarchically as follows:

bookingDate
--tourGrade
----ageBand
------price

Types of pricing unit

There are two fundamental types of pricing unit – per-person and per-group.

Per-person pricing schedule

If the pricing is per-person, then the total price of the booking will be directly proportional to the number of participants (passengers) of each type that are booking the product; i.e., a direct multiple of the per-person price.

The only pricing unit specifier for per-person pricing is “per person”, given in the pricingUnit field; i.e.:

  • "pricingUnit": "per person"
Pricing unitExample productMeaning
"per person"10040WORLDPer-person pricing – the unit price refers to the price for an individual participant.<br />Some products have tiered pricing arrangements; i.e., a different per-person price can apply if certain numbers and combinations of participants in a particular age band are booking the product; e.g.:<br /><ul><li>1-2 adults: $50 per person</li><li>3-4 adults: $45 per person</li></ul><br />Whether a range is available to be booked depends on whether the customer’s desired passenger mix satisfies the minimumCountRequired and maximumCountRequired fields in each item of the ageBandPrices array.

Per-group pricing

If the pricing is per-group, then the total price of the booking will depend on the number of groups and types of group that ideally accommodate the participant mix.

The following pricing schedules follow “per-group” logic:

  • "pricingUnit": "per vehicle"
  • "pricingUnit": "per car"
  • "pricingUnit": "per group"
  • "pricingUnit": "per boat"
  • "pricingUnit": "per package"
  • "pricingUnit": "per jetski"
  • "pricingUnit": "per vessel"
  • "pricingUnit": "per helicopter"
  • "pricingUnit": "per room"
  • "pricingUnit": "per bike"
  • "pricingUnit": "per flight"
  • "pricingUnit": "per plane"
  • "pricingUnit": "per couple"

Eligibility for a certain individual pricing schedule; or, for inclusion in a particular group type, depends on the tour grade for the product, the type of participant (e.g., the age-band they fall into) and the date of the booking.

Group pricing schedules

Pricing unitExample productMeaning
"per group"10847P42Per-group pricing – the unit price is calculated according to the number of groups the specified passenger will fit into rather than the exact number of participants. minimumCountRequired and maximumCountRequired must be considered as these fields relate to the available group sizes.
"per room"6279P26Per-room pricing relates the room price, which depends on the number of participants making the booking.
"per package"25941P70Per-package pricing refers to products that are sold as part of a package; for example a family package stipulating a passenger mix of two adults and two children
"per vehicle"6154SHOPPer-vehicle pricing is calculated according to the number of vehicles required for the specified passenger mix rather than the exact number of participants. minimumCountRequired and maximumCountRequired must be considered as these fields relate to the occupancy limitations for each vehicle. The minimum price will depend on the rate for a single vehicle.
"per car"10175P10Per-car pricing – identical to “per vehicle”, but refers specifically to vehicles that are cars.
"per boat"11121P40Per-boat pricing – identical to “per vehicle”, but refers specifically to vehicles that are boats.
"per jetski"28965P127Per-jetski pricing – identical to “per vehicle”, but refers specifically to vehicles that are jet-skis.
"per vessel"17295P24Per-vessel pricing – identical to “per vehicle”, but refers specifically to maritime vessels that are not strictly boats.
"per helicopter"12189P23Per-helicopter pricing – identical to “per vehicle”, but refers specifically to vehicles that are helicopters.
"per bike"17448P8Per-bike pricing – identical to “per vehicle”, but refers specifically to vehicles that are bikes.
"per flight"28965P134Per-flight pricing – identical to “per vehicle”, but refers specifically to the act of being aboard a flying vehicle.
"per plane"14876P5Per-plane pricing – identical to “per vehicle”, but refers specifically to vehicles that are aeroplanes.

Interpreting response objects by example

In this section, we’ll have a look at snippets from the response objects received from the /booking/availability/tourgrades/pricingmatrix service and interpret the results.

Per-person pricing

Request object
{
  "productCode": "10040WORLD",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}

Response snippet

Note: pricingMatrix is an array of objects that detail the available pricing schedules for the product:

"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per person",
    "bookingDate": "2019-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 13.85,
            "priceFormatted": "$13.85",
            "merchantNetPrice": 11.05,
            "merchantNetPriceFormatted": "$11.05",
            "minNoOfTravellersRequiredForPrice": 1
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 0,
        "maximumCountRequired": 15
      },
      {
        "bandId": 2,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 6.92,
            "priceFormatted": "$6.92",
            "merchantNetPrice": 5.53,
            "merchantNetPriceFormatted": "$5.53",
            "minNoOfTravellersRequiredForPrice": 1
          }
        ],
        "sortOrder": 2,
        "minimumCountRequired": 0,
        "maximumCountRequired": 15
      },
      {
        "bandId": 3,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 0,
            "priceFormatted": "$0.00",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "minNoOfTravellersRequiredForPrice": 1
          }
        ],
        "sortOrder": 3,
        "minimumCountRequired": 0,
        "maximumCountRequired": 15
      },
      {
        "bandId": 5,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 10.39,
            "priceFormatted": "$10.39",
            "merchantNetPrice": 8.3,
            "merchantNetPriceFormatted": "$8.30",
            "minNoOfTravellersRequiredForPrice": 1
          }
        ],
        "sortOrder": 4,
        "minimumCountRequired": 0,
        "maximumCountRequired": 15
      }
    ]
  }
]

In this example, four age bands (1, 2, 3 and 5) have pricing information available. These numerically-identified age bands are the age bands allowed to book the product. Details of the age ranges that the product operator has defined are available from the /product service.

A call to /product regarding 10040WORLD yields the following information:

"ageBands": [
  {
    "sortOrder": 1,
    "ageFrom": 13,
    "ageTo": 64,
    "adult": true,
    "bandId": 1,
    "pluralDescription": "Adults",
    "treatAsAdult": true,
    "count": 0,
    "description": "Adult"
  },
  {
    "sortOrder": 2,
    "ageFrom": 65,
    "ageTo": 99,
    "adult": false,
    "bandId": 5,
    "pluralDescription": "Seniors",
    "treatAsAdult": true,
    "count": 0,
    "description": "Senior"
  },
  {
    "sortOrder": 3,
    "ageFrom": 4,
    "ageTo": 12,
    "adult": false,
    "bandId": 2,
    "pluralDescription": "Children",
    "treatAsAdult": false,
    "count": 0,
    "description": "Child"
  },
  {
    "sortOrder": 4,
    "ageFrom": 0,
    "ageTo": 3,
    "adult": false,
    "bandId": 3,
    "pluralDescription": "Infants",
    "treatAsAdult": false,
    "count": 0,
    "description": "Infant"
  }

Product operators choose the age bands available for their product from the following five categories and define the age ranges that pertain to each band; i.e.:

bandIddescription
1Adult
2Child
3Infant
4Youth
5Senior

For this product, the age bands have been defined as follows:

bandIddescriptionageFromageTo
1Adult1364
5Senior6599
2Child412
3Infant03

Therefore, for this product, the following pricing applies:

Passenger typeNumberPrice
Adult1-15$13.85 per person
Senior1-15$10.39 per person
Child1-15$6.92 per person
Infant1-15free ($0)

Per-person pricing might depend on the mix of passengers booking the tour. In the following example (5010SYDNEY), a “48 Hour Family Pass Ticket” has a different price for children depending on how many are participating, which we’ll see in the following snippet.

Response snippet
"tourGrades": [
  {
    "sortOrder": 1,
    "gradeCode": "14HFAM",
    "gradeTitle": "48 Hour Family Pass Ticket",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 133.47,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$133.47",
                "merchantNetPrice": 106.62,
                "merchantNetPriceFormatted": "$106.62"
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 1
          },
          {
            "bandId": 2,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 0,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$0.00",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00"
              }
            ],
            "sortOrder": 2,
            "minimumCountRequired": 2,
            "maximumCountRequired": 2
          },
          {
            "bandId": 3,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 0,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$0.00",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00"
              }
            ],
            "sortOrder": 3,
            "minimumCountRequired": 0,
            "maximumCountRequired": null
          }
        ]
      },
      {
        "sortOrder": 2,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 133.47,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$133.47",
                "merchantNetPrice": 106.62,
                "merchantNetPriceFormatted": "$106.62"
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 1
          },
          {
            "bandId": 2,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 3.71,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$3.71",
                "merchantNetPrice": 2.96,
                "merchantNetPriceFormatted": "$2.96"
              }
            ],
            "sortOrder": 2,
            "minimumCountRequired": 3,
            "maximumCountRequired": 4
          },
          {
            "bandId": 3,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 0,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$0.00",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00"
              }
            ],
            "sortOrder": 3,
            "minimumCountRequired": 0,
            "maximumCountRequired": null
          }
        ]
      }
    ]
  },
  
]
Interpretation

To be eligible for a family pass ticket, the group must consist of an adult and at least two children.

Passenger mixAdult priceChild priceInfant price
1 Adult +<br />1 ChildN/AN/AN/A
1 Adult +<br />2 Children +<br />Any infants$133.47FREEFREE
1 Adult +<br />3-4 Children +<br />Any infants$133.47$3.71FREE

Tiered per-person pricing

In this example, we see a per-person pricing schedule with a tiered arrangement, where the per-person price decreases depending on how many people are booking the tour, but the total price is still calculated as the sum of the individual per-person prices rather than an overall ‘group’ price.

Request object
{
  "productCode": "17972P102",
  "currencyCode": "USD",
  "month": "08",
  "year": "2019"
}
Response snippet
"tourGrades": [
  {
    "sortOrder": 1,
    "gradeCode": "TG1",
    "gradeTitle": "Arrival transfer",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 52.45,
                "priceFormatted": "$52.45",
                "merchantNetPrice": 40.87,
                "merchantNetPriceFormatted": "$40.87",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 1,
            "minimumCountRequired": 1
          }
        ]
      },
      {
        "sortOrder": 2,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 26.22,
                "priceFormatted": "$26.22",
                "merchantNetPrice": 20.44,
                "merchantNetPriceFormatted": "$20.44",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 2,
            "minimumCountRequired": 2
          }
        ]
      },
      {
        "sortOrder": 3,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 17.91,
                "priceFormatted": "$17.91",
                "merchantNetPrice": 13.62,
                "merchantNetPriceFormatted": "$13.62",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 3,
            "minimumCountRequired": 3
          }
        ]
      },
      {
        "sortOrder": 4,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 19.19,
                "priceFormatted": "$19.19",
                "merchantNetPrice": 14.99,
                "merchantNetPriceFormatted": "$14.99",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 4,
            "minimumCountRequired": 4
          }
        ]
      },
      {
        "sortOrder": 5,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 15.35,
                "priceFormatted": "$15.35",
                "merchantNetPrice": 12.25,
                "merchantNetPriceFormatted": "$12.25",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 5,
            "minimumCountRequired": 5
          }
        ]
      },
      {
        "sortOrder": 6,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 12.66,
                "priceFormatted": "$12.66",
                "merchantNetPrice": 10.08,
                "merchantNetPriceFormatted": "$10.08",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 6,
            "minimumCountRequired": 6
          }
        ]
      },
      {
        "sortOrder": 7,
        "pricingUnit": "per person",
        "bookingDate": "2019-08-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 10.94,
                "priceFormatted": "$10.94",
                "merchantNetPrice": 8.72,
                "merchantNetPriceFormatted": "$8.72",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "maximumCountRequired": 7,
            "minimumCountRequired": 7
          }
        ]
      }
    ]
  }
Interpretation
TravelersPer-person priceTotal price
1$52.45$52.45
2$26.22$52.44
3$17.91$53.73
4$19.19$76.76
5$15.35$76.75
6$12.66$75.96
7$10.94$76.58

Per-group pricing

Request object
{
  "productCode": "10847P42",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per group",
    "bookingDate": "2019-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 390,
            "minNoOfTravellersRequiredForPrice": 1,
            "priceFormatted": "$390.00",
            "merchantNetPrice": 339.74,
            "merchantNetPriceFormatted": "$339.74"
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 390,
            "minNoOfTravellersRequiredForPrice": 2,
            "priceFormatted": "$390.00",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00"
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 10
      }
    ]
  }
]
Interpretation
  • “$390 per group of up to 10 adults”

Per-room pricing

Request object
{
  "productCode": "100245P40",
  "currencyCode": "USD",
  "month": "08",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
{
    "sortOrder": 1,
    "pricingUnit": "per room",
    "bookingDate": "2019-08-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 110,
            "minNoOfTravellersRequiredForPrice": 1,
            "priceFormatted": "$110.00",
            "merchantNetPrice": 95.85,
            "merchantNetPriceFormatted": "$95.85"
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 110,
            "minNoOfTravellersRequiredForPrice": 2,
            "priceFormatted": "$110.00",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00"
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 10
      }
    ]
  }
]
Interpretation
  • “$110 per group of up to 10 adults”

Per-package pricing

Request object
{
  "productCode": "25941P70",
  "currencyCode": "USD",
  "month": "02",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per package",
    "bookingDate": "2019-02-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 87.7,
            "minNoOfTravellersRequiredForPrice": 1,
            "priceFormatted": "$87.70",
            "merchantNetPrice": 67.23,
            "merchantNetPriceFormatted": "$67.23"
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 87.7,
            "minNoOfTravellersRequiredForPrice": 2,
            "priceFormatted": "$87.70",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00"
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 10
      }
    ]
  }
]
Interpretation
  • “$87.70 per group of up to 10 adults”

Per-vehicle pricing

Request object
{
  "productCode": "20190P4",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per vehicle",
    "bookingDate": "2019-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 250,
            "minNoOfTravellersRequiredForPrice": 1,
            "priceFormatted": "$250.00",
            "merchantNetPrice": 186.38,
            "merchantNetPriceFormatted": "$186.38"
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 250,
            "minNoOfTravellersRequiredForPrice": 2,
            "priceFormatted": "$250.00",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00"
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 7
      }
    ]
  }
]
Interpretation
  • “$250 per group of up to 7 adults”

Per-car pricing

Request object
{
  "productCode": "10175P10",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}

Response snippet

"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per car",
    "bookingDate": "2019-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 98.08,
            "priceFormatted": "$98.08",
            "merchantNetPrice": 78.34,
            "merchantNetPriceFormatted": "$78.34",
            "minNoOfTravellersRequiredForPrice": 1
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 98.08,
            "priceFormatted": "$98.08",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "minNoOfTravellersRequiredForPrice": 2
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 3
      }
    ]
  }
]
Interpretation
  • “$98.08 per group of up to 3 adults”

Per-boat pricing

Request object
{
  "productCode": "11121P40",
  "currencyCode": "USD",
  "month": "08",
  "year": "2018"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per boat",
    "bookingDate": "2018-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 266.21,
            "merchantNetPrice": 226.81,
            "merchantNetPriceFormatted": "$226.81",
            "priceFormatted": "$266.21",
            "minNoOfTravellersRequiredForPrice": 1
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 266.21,
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "priceFormatted": "$266.21",
            "minNoOfTravellersRequiredForPrice": 2
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 2
      }
    ]
  }
]
Interpretation
  • “$266.21 per group of up to 2 adults”

Per-jetski pricing

Request object
{
  "productCode": "28965P127",
  "currencyCode": "USD",
  "month": "08",
  "year": "2018"
}
Response snippet
"tourGrades": [
  {
    "sortOrder": 1,
    "gradeCode": "TG1",
    "gradeTitle": "20 minutes for 1 person",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per jetski",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 55.46,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$55.46",
                "merchantNetPrice": 47.25,
                "merchantNetPriceFormatted": "$47.25"
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 1
          }
        ]
      }
    ]
  },
  {
    "sortOrder": 2,
    "gradeCode": "TG3",
    "gradeTitle": "20 minutes for 2 persons",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per jetski",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 66.55,
                "minNoOfTravellersRequiredForPrice": 1,
                "priceFormatted": "$66.55",
                "merchantNetPrice": 56.7,
                "merchantNetPriceFormatted": "$56.70"
              },
              {
                "sortOrder": 2,
                "currencyCode": "USD",
                "price": 66.55,
                "minNoOfTravellersRequiredForPrice": 2,
                "priceFormatted": "$66.55",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00"
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 2
          }
        ]
      }
    ]
  }
]
Interpretation

This example shows how group prices can differ according to the size of the group in question. In this case, two adults can ride together on a two-person jet ski, whereas a single adult requires his or her own jet ski, and therefore the unit price is slightly higher for the single adult.

TravelersVehicle typePrice per jet skiPrice per person
1Single-person jet ski$55.46$55.46
2Two-person jet ski$66.55$33.275

Per-vessel pricing

Request object
{
  "productCode": "17295P24",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per vessel",
    "bookingDate": "2019-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 799,
            "priceFormatted": "$799.00",
            "merchantNetPrice": 680.75,
            "merchantNetPriceFormatted": "$680.75",
            "minNoOfTravellersRequiredForPrice": 1
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 799,
            "priceFormatted": "$799.00",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "minNoOfTravellersRequiredForPrice": 2
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 12
      }
    ]
  }
]
Interpretation
  • “$799.00 per group of up to 12 adults”

Per-helicopter pricing

Request object
{
  "productCode": "12189P23",
  "currencyCode": "USD",
  "month": "08",
  "year": "2018"
}
Response snippet
"tourGrades": [
  {
    "sortOrder": 1,
    "gradeCode": "TG1",
    "gradeTitle": "Private Helicopter 1 to 2 Pax",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per helicopter",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 1714.83,
                "priceFormatted": "$1,714.83",
                "merchantNetPrice": 1461.03,
                "merchantNetPriceFormatted": "$1,461.03",
                "minNoOfTravellersRequiredForPrice": 1
              },
              {
                "sortOrder": 2,
                "currencyCode": "USD",
                "price": 1714.83,
                "priceFormatted": "$1,714.83",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00",
                "minNoOfTravellersRequiredForPrice": 2
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 2
          }
        ]
      }
    ]
  },
  {
    "sortOrder": 2,
    "gradeCode": "TG2",
    "gradeTitle": "Private Helicopter 1 to 3 Pax",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per helicopter",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 2047.41,
                "priceFormatted": "$2,047.41",
                "merchantNetPrice": 1744.4,
                "merchantNetPriceFormatted": "$1,744.40",
                "minNoOfTravellersRequiredForPrice": 1
              },
              {
                "sortOrder": 2,
                "currencyCode": "USD",
                "price": 2047.41,
                "priceFormatted": "$2,047.41",
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00",
                "minNoOfTravellersRequiredForPrice": 2
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 3
          }
        ]
      }
    ]
  }
]
Interpretation
TravelersVehicle typePrice per helicopterPrice per person
11-2-person helicopter$1,714.83$1,714.83
21-2-person helicopter$1,714.83$857.415
31-3-person helicopter$2,047.41$682.47

Per-bike pricing

Request object
{
  "productCode": "17448P8",
  "currencyCode": "USD",
  "month": "08",
  "year": "2018"
}

Response snippet

"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per bike",
    "bookingDate": "2018-06-01",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 208.53,
            "priceFormatted": "$208.53",
            "merchantNetPrice": 177.67,
            "merchantNetPriceFormatted": "$177.67",
            "minNoOfTravellersRequiredForPrice": 1
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 208.53,
            "priceFormatted": "$208.53",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "minNoOfTravellersRequiredForPrice": 2
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 2
      }
    ]
  }
]
Interpretation
  • “$208.53 per bike, with up to two adults per bike”

Per-flight pricing

Request object
{
  "productCode": "28965P134",
  "currencyCode": "USD",
  "month": "08",
  "year": "2018"
}
Response snippet
"tourGrades": [
  {
    "sortOrder": 1,
    "gradeCode": "TG1",
    "gradeTitle": "Individual flight",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per flight",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 61.01,
                "merchantNetPrice": 51.98,
                "merchantNetPriceFormatted": "$51.98",
                "priceFormatted": "$61.01",
                "minNoOfTravellersRequiredForPrice": 1
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 1
          }
        ]
      }
    ]
  },
  {
    "sortOrder": 2,
    "gradeCode": "TG2",
    "gradeTitle": "Double",
    "pricingMatrix": [
      {
        "sortOrder": 1,
        "pricingUnit": "per flight",
        "bookingDate": "2018-06-01",
        "ageBandPrices": [
          {
            "bandId": 1,
            "prices": [
              {
                "sortOrder": 1,
                "currencyCode": "USD",
                "price": 94.28,
                "merchantNetPrice": 80.33,
                "merchantNetPriceFormatted": "$80.33",
                "priceFormatted": "$94.28",
                "minNoOfTravellersRequiredForPrice": 1
              },
              {
                "sortOrder": 2,
                "currencyCode": "USD",
                "price": 94.28,
                "merchantNetPrice": 0,
                "merchantNetPriceFormatted": "$0.00",
                "priceFormatted": "$94.28",
                "minNoOfTravellersRequiredForPrice": 2
              }
            ],
            "sortOrder": 1,
            "minimumCountRequired": 1,
            "maximumCountRequired": 2
          }
        ]
      }
    ]
  }
]
Interpretation
TravelersgradeTitlePrice per flightPrice per person
1Individual flight$61.01$61.01
2Double$94.28$47.14

Per-plane pricing

Request object
{
  "productCode": "14876P5",
  "currencyCode": "USD",
  "month": "06",
  "year": "2019"
}
Response snippet
"pricingMatrix": [
  {
    "sortOrder": 1,
    "pricingUnit": "per plane",
    "bookingDate": "2019-01-02",
    "ageBandPrices": [
      {
        "bandId": 1,
        "prices": [
          {
            "sortOrder": 1,
            "currencyCode": "USD",
            "price": 433.03,
            "priceFormatted": "$433.03",
            "merchantNetPrice": 391.99,
            "merchantNetPriceFormatted": "$391.99",
            "minNoOfTravellersRequiredForPrice": 1
          },
          {
            "sortOrder": 2,
            "currencyCode": "USD",
            "price": 433.03,
            "priceFormatted": "$433.03",
            "merchantNetPrice": 0,
            "merchantNetPriceFormatted": "$0.00",
            "minNoOfTravellersRequiredForPrice": 2
          }
        ],
        "sortOrder": 1,
        "minimumCountRequired": 1,
        "maximumCountRequired": 3
      }
    ]
  }
]
Interpretation
  • “$433.03 per group of up to three people”

Working with age bands

Age bands

The available age bands for a product, such as adult, child, infant, etc., are returned by the /product service. The customer can select a different number of people from each age band during the price check and checkout process.

Why have age bands?

Tour and experience product operators can set different prices for (and impose different rules on) those wishing to make a booking for their product according to how old they are.

For example, suppliers might choose to charge people 18 years and older (‘adults’) the full ticket price, while ‘children’ can book at a lower price.

Or, the tour operator may only allow children to make a group booking for the tour so long as the group contains ‘at least one adult’.

Viator provides five categories (age bands) that product operators can use to segregate travelers into age groups (the limits of which they also define) in order to set pricing and traveler-count participation rules for their product according to the age band categories.

Supported age band categories

The age bands supported by the Viator API are as follows:

bandIdDescription
1Adult
2Child
3Infant
4Youth
5Senior

The names and corresponding numeric identifiers of these categories are fixed as in the table above (i.e., 1 is always Adult); however, the exact age range to which each category pertains must be defined manually by the supplier.

The maximum and minimum ages that each age band describes for each product can be retrieved from the /product service.

Example of age band definitions

For example, a call to /product regarding 10040WORLD yields the following ageBands array within its response object:

"ageBands": [
  {
    "sortOrder": 1,
    "ageFrom": 13,
    "ageTo": 64,
    "adult": true,
    "bandId": 1,
    "pluralDescription": "Adults",
    "treatAsAdult": true,
    "count": 0,
    "description": "Adult"
  },
  {
    "sortOrder": 2,
    "ageFrom": 65,
    "ageTo": 99,
    "adult": false,
    "bandId": 5,
    "pluralDescription": "Seniors",
    "treatAsAdult": true,
    "count": 0,
    "description": "Senior"
  },
  {
    "sortOrder": 3,
    "ageFrom": 4,
    "ageTo": 12,
    "adult": false,
    "bandId": 2,
    "pluralDescription": "Children",
    "treatAsAdult": false,
    "count": 0,
    "description": "Child"
  },
  {
    "sortOrder": 4,
    "ageFrom": 0,
    "ageTo": 3,
    "adult": false,
    "bandId": 3,
    "pluralDescription": "Infants",
    "treatAsAdult": false,
    "count": 0,
    "description": "Infant"
  }

For this product, the age bands have been defined as follows:

bandIddescriptionageFromageTo
1Adult1364
5Senior6599
2Child412
3Infant03

Product operators must define at least one age band for their tour, and there are no ‘default’ age ranges. Therefore, if the product operator has only specified a single ‘adult’ age band covering ages 18-99, it must be assumed that only people aged 18-99 are eligible to book the tour, essentially excluding children and centenarians in this case.

FieldTypeDefinition
sortOrderintegerthe sort order for this age band
adultbooleantrue if this age band is the ‘adult’ age band
treatAsAdultbooleantrue if this age band can book the tour without the need for adult accompaniment

Note: bandId must be supplied in the request body of the following services:

Age bands are referenced by their bandId in the responses from the following services:

How to report a product issue

Occasionally, a product schema in the Viator database will contain incorrect or invalid information. Usually, this occurs due to a mistake made by the supplier of the product when creating the product or updating its details.

Nonetheless, it’s in all our best interests for product information to be accurate and up-to-date; therefore, if you discover a problem with a product, we would greatly appreciate it if you could report the error through our product issue reporting form.

How to use the product issue reporting form

  1. Navigate to the product issue reporting page
  2. Fill in the Reporter, Supplier ID, Product Code and Booking ID fields:
FieldHow to fill it inExample
ReporterEnter your email address for tracking or correspondenceyou@emailserver.com
Supplier IDEnter the value returned in the supplierCode field by the /product service for the product in question.3072
Product CodeEnter the value returned in the code field by the /product service for the product in question.3072LASALL
Booking IDLeave this field blank
  1. In the Reason box below, choose Content by clicking on its radio selector. A list of categories will appear, with meanings as follows:
CategoryIncluded issues
Additional Infoclauses in the additionalInfo array in the response from /product; e.g., departure time or hotel pick-up information
Availability & BlockoutsN/A
Booking DetailsN/A
Highlightshighlights array items in the response from /product
Inclusions / Exclusionsinclusions or exclusions array items in the response from /product
ImagesproductPhotos and userPhotos returned by /product or /product/photos
Product Titletitle in the response from /product, /search/products, /search/products/codes and /search/products/freetext
Product Descriptionsdescription and shortDescription in the response from /product
SAPIN/A
Tour Options & Pricingpricing issues; e.g. when the value of merchantNetPrice is 0; or, if merchantNetPrice > price
Taxonomy<ul><li>destination issues in response from /taxonomy/destination</li><li>category / subcategory issues in response from /taxonomy/categories</li></ul>
Translation Incorrectmistakes in any natural-language field in the response from any service where translationLevel is non-zero
TVRMN/A
VUC incorrectN/A
  1. After selecting the category of issue from the options shown, fill-in the Description / Action Required box with a good, clear description of the problem and any specific additional actions you would like us to take
  2. Click Submit to send the report

<figure> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/tae-report-a-product-issue.jpg" alt=“Tripadvisor experiences report a product form”/> <figcaption>Example Report a Product Issue form</figcaption> </figure>

Once your report has been submitted, a member of our Supplier Support Team will contact the supplier of the product in question to resolve any problems with their listing.

Selling on-request products

This section explains what merchant API partners need to do in order to be granted access to (and, ultimately, sell) the many on-request products available in Viator’s product catalogue.

‘Freesale’ vs ‘on-request’ products

Among the products in our inventory, a major differentiating feature is whether they are ‘freesale’ or ‘on-request’:

  • Freesale products are always available to be booked on their days of operation; therefore, when a freesale product is purchased, the booking is confirmed and the customer is charged immediately.
  • On-request products only operate at the discretion of the supplier, who must confirm (or reject) each booking request, which will remain ‘pending’ in the interim. The customer is only charged once confirmation is received.

Access to on-request products

By default, you will only have access to the freesale product range; access to the on-request product range is restricted on account of the extra complexities involved with handling this kind of booking.

Should I elect to sell on-request products?

Business case for including on-request products in your inventory

While the majority of products in our inventory are ‘freesale’, a significant proportion remain ‘on-request’. Upgrading your booking platform to support on-request products can lead to an increase in revenue of between 5% and 13%, depending on the locale(s) in which you operate.

LocaleRevenue increase %
en8%
es8%
fr11%
de10%
pt5%
nl12%
it10%
ja10%
sv8%
no8%
da13%
tw13%
zh6%

Having a wider range of products on offer can be a key differentiator with respect to your competitors.

Customers often purchase multiple products in the same session – if the product they’re looking for isn’t available on your platform, they are likely to seek a competitor with a more complete range of products for sale.

Logistical considerations to enable on-request products

In order to sell on-request products, you will need to:

  • Modify your back-end systems to support extra logic and API requests
  • Establish and support an extra, email-based communications channel with your customers
  • Create some email templates
  • Modify your platform’s front end to accommodate the extra steps required in the booking process
  • Write copy that ensures customers clearly understand that they are booking a product that will not be confirmed or charged immediately

However, as the on-request booking confirmation process is fully automated, you will not need to:

  • Undertake any additional manual steps compared with booking a freesale product
  • Personally contact the product supplier or our partner support team

Instead, checking the status of bookings (whether confirmed or not) can be accomplished using the /booking/status and /booking/status/items services. These services can be polled periodically to determine the confirmation status of your bookings.

<u>Note</u>: We recommend using the /booking/status/items service to poll for booking statuses, as it is both faster and can be polled more frequently than /booking/status, which can only be polled once every thirty minutes.

How to support on-request products

Product detail page

Managing customer expectations is a key factor in supporting on-request products on your booking platform.

Make clear mention that this is a product for which confirmation will not be received immediately, but rather within 48 hours of making the booking.

This fact, as well as other pertinent tidbits, can be found in the additionalInfo array in the response from /product. It is mandatory that all clauses in the additionalInfo array are clearly displayed on your product detail page.

<figure> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/additional-info-on-request-clause.jpg" alt=“Additional info displayed on a product page on the Viator site”/> <figcaption>Additional info displayed on a product page on the Viator site </figcaption> </figure>

Check-out

As you will only charge the customer’s credit card once the on-request booking is confirmed (i.e., after we have received confirmation of the booking from the product supplier) it’s best to display a message to this effect at a prominent point of the check-out flow for all on-request products.

<figure> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/checkout-flow-confirmation-info.jpg" alt=“Example checkout-flow instruction on the Viator site”/> <figcaption>Example checkout-flow instruction on the Viator site</figcaption> </figure>

In this way, customers can be reassured that they are not being charged for a booking that may never be confirmed, thereby minimizing needless calls to your customer service team.

Combination purchases

If a single booking includes both freesale (instantly confirmed) and on-request products, only the amount for the freesale product should be charged immediately; the portion corresponding to the on-request booking should only be charged once confirmation is received.

Until that time, a pre-authorization should be held against the customer’s credit card until confirmation is received.

It is important that you clearly differentiate between products that are confirmed and those that are pending confirmation, and communicate the status of each and that the pre-authorization will only finalize once the on-request products are confirmed.

Confirmation page

Changes will need to be made to your confirmation page because it will not be possible for your customer to download a voucher after completing an on-request booking.

Vouchers for freesale products, however, must be made available immediately following the completion of the booking process.

Email communications

You will need to create email templates for <u>all</u> the following scenarios:

  • Confirmation emails for bookings with on-request products should indicate that the item is pending confirmation from the supplier; and, that confirmation for this activity will take up to 48 hours, depending on availability.
  • If the on-request booking is confirmed by the supplier (this time including the voucher details)
  • If the on-request booking is rejected
  • If multiple on-request products have been booked:
    • If all items have been accepted/confirmed
    • If all items were rejected
    • If there is a mixture of acceptance and rejection; i.e., ‘pending’ + ‘rejected’ + ‘cancelled’ + ‘amended’ and so forth.
  • If a mixture of freesale and on-request products are booked at the same time; i.e., in the same cart or booking

<u>Note</u>: When a booking is declined, it is useful to mention that the customer’s card was not charged.

Example email for an on-request booking pending confirmation:

<figure> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/on-request-confirmation-email-1.jpg" alt=“Viator website showing translation attribution”/> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/on-request-confirmation-email-2.jpg" alt=“Viator website showing translation attribution”/> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/on-request-confirmation-email-3.jpg" alt=“Viator website showing translation attribution”/> </figure>

Confirmation time-outs resulting in rejection

As mentioned above, once a booking for an on-request product is made, it remains in a ‘pending’ state, awaiting confirmation by the supplier. The supplier has the option of ‘confirming’ or ‘rejecting’ the booking.

Such bookings will not remain ‘pending’ indefinitely, however. If the supplier has not confirmed the booking within 72 hours – or if they have not confirmed the booking by the time it reaches 24 hours from departure – our systems will automatically reject the booking, and this will be reflected in the response from the /booking/status/items and /booking/status services.

There will be no indication that the rejection occurred on account of the supplier being unable to perform their duties. Therefore, you should simply inform the customer that, for reasons out of your control, this on-request tour was unavailable.

Building in the sandbox environment

Upgrading your booking platform to support on-request products will require you to build and test this functionality in the sandbox environment. However, as no actual booking requests are made with the supplier when using a sandbox-only API-key, you will need to contact our API tech support team at apitechsupport@viator.com and request that the booking be confirmed or rejected as you require.

While necessary, this is a manual process. We’d genuinely appreciate your effort in keeping the number of these requests to a minimum.

Certification and going live

Once you have completed all tasks mentioned here and sent your Viator account manager the email copy for the different scenarios described above, we will change the status of your product API-key to include on-request products.

Localization and translation

Foreign language products

The products available through the Viator API have been created in a variety of languages, often by the suppliers of those products themselves.

Although the majority of these have been created in English, many have been created in other languages. For example, a tour that operates in Paris might have been created in French.

Viator provides translation services to localize product descriptions to the language of the locale in which they are being presented. In this way, products with descriptions – for example, in French – can be displayed in English on English-language websites. Conversely, products with English-language-descriptions can be displayed in French on French-language websites.

  • Note: product descriptions are translated into the language specified in the Accept-Language header parameter in the request to each endpoint.

Human and machine translation

Some products have been translated by actual humans – ‘human translated’ – while others have been automatically translated using Google Translate – ‘machine translated’.

The type of translation that has been applied to a product (if any) is indicated by its translationLevel, a numeric specifer with meanings as follows:

translationLevelMeaning
0The product was created by the supplier in the language you specifed using the Accept-Language header parameter in the request; i.e., the natural-language text in this response has not been translated
80All product information has been <u>machine translated</u>
90 or 100All product information has been <u>human translated</u>

Therefore, any product with a non-zero translationLevel has been translated either by a human or via an automatic process.

The translationLevel field is returned in the response objects from the following services:

When performing a product search using any of these services, you will receive - by default - products with a translationLevel of:

  • 0 (products that are in the language you specified in Accept-Language and are configured for your API-keys), and
  • 90 or 100 (products that have been <u>fully human translated</u>)

Accessing machine-translated products

If your implementation can support the large number of products available that are machine translated, you can.

However, access to the considerable volume of machine-translated products (level 80), is <u>not granted by default</u>.

To access machine-translated products, you will need to:

  1. Request access to machine-translated products in sandbox from your Business Development account manager.
  2. Test your site with sandbox to ensure that you can download and display all the available content.
  3. Have your Business Development account manager review your implementation and grant access in the production environment.

Merchant pricing

Many of the endpoints in the Viator API return pricing information. Due to the necessity of supporting legacy implementations, some pricing fields may not be named in an intuitive way.

This section seeks to clarify what each of the pricing fields returned by each endpoint actually refer to and how you need to use this information in your implementation.

Categories of pricing

CategoryMeaning
Suggested retail priceThe recommended retail price for the product and the price that the product is sold at on the Viator site
Merchant net rateThe amount that Viator will invoice the merchant for this sale, excluding the transaction fee
Merchant total priceThe total amount that Viator will invoice the merchant for this sale, including the transaction fee
ServiceSuggested retail priceMerchant net rate
/search/productsprice, priceFormattedmerchantNetPriceFrom, merchantNetPriceFromFormatted
/productprice, priceFormatted, priceFrom, priceFromFormattedmerchantNetPriceFrom, merchantNetPriceFromFormatted
/booking/availabilityretailPrice, retailPriceFormattedmerchantNetPrice, merchantNetPriceFormatted
/booking/availability/tourgradesretailPrice, retailPriceFormattedmerchantNetPrice, merchantNetPriceFormatted
/booking/availability/tourgrades/pricingmatrixprice, priceFormattedmerchantNetPrice, merchantNetPriceFormatted
/booking/bookN/AmerchantNetPrice, merchantNetPriceFormatted, lastRetailPrice, lastRetailPriceFormatted
/booking/pricingmatrixprice, priceFormattedmerchantNetPrice, merchantNetPriceFormatted
/booking/calculatepriceN/AmerchantNetPrice, merchantNetPriceFormatted, lastRetailPrice, lastRetailPriceFormatted, itineraryFromPrice, itineraryFromPriceFormatted, itineraryNewPrice, itineraryNewPriceFormatted
/booking/pastbookingN/AmerchantNetPrice, merchantNetPriceFormatted, lastRetailPrice, lastRetailPriceFormatted,
/booking/mybookingsN/AmerchantNetPrice, merchantNetPriceFormatted, lastRetailPrice, lastRetailPriceFormatted

The following services return the merchant total price (i.e., the merchant net rate + transaction fee) in the fields shown:

ServiceMerchant total price fields
/booking/bookprice, priceFormatted, totalPrice, totalPriceFormatted, priceUSD, totalPriceUSD
/booking/calculatepriceprice, priceFormatted, priceUSD, totalPrice, totalPriceFormatted, totalPriceUSD
/booking/pastbookingprice, priceFormatted, totalPrice, totalPriceFormatted, priceUSD, totalPriceUSD,
/booking/mybookingsprice, priceFormatted, priceUSD, totalPrice, totalPriceFormatted, totalPriceUSD

Using the pricing fields

Let’s have a look at the various pricing fields for a specific product - the Grand Canyon All-American Helicopter Tour (product code: 2280AAHT).

A search for this product (at the time of writing) on the Viator.com site gives the ‘from’ price of the tour as $601.11:

<figure> <img src=“https://docs.viator.com/partner-api/resources/merchant/technical/img/suggested-retail-price.jpg" alt="‘from’ price on viator.com product detail page”/> <figcaption>Retail price shown on viator.com</figcaption> </figure>

This value comes from the price or priceFormatted fields in the response from /product for this tour; i.e.,:

{
  ...,
  "price": 601.11,
  "priceFormatted": "$601.11",
  ...
}

Essentially, this value is the price that the product is sold at on the viator site, and is therefore the suggested retail price; i.e., the price at which we recommend you advertise and sell the product for.

It is also the price of the tour grade with the lowest price; in this case, the “Earlybird A-Star” tour grade detailed here:

{
    "sortOrder": 5,
    "currencyCode": "AUD",
    "langServices": {
        "en/SERVICE_AUDIO": "English - Audio"
    },
    "gradeCode": "EB_ASTAR_SP",
    "merchantNetPriceFrom": 555.37,
    "priceFrom": 601.11,
    "priceFromFormatted": "$601.11",
    "merchantNetPriceFromFormatted": "$555.37",
    "gradeTitle": "Special: Earlybird A-Star",
    "gradeDepartureTime": "",
    "gradeDescription": "Special Offer: Receive a discounted seat for the Grand Canyon All American Helicopter Tour departing between 6:45am and 7am on an A-Star helicopter",
    "defaultLanguageCode": "en"
},

As you can see, the “suggested retail price” is given in the priceFrom field.

Low and zero-margin products

When setting the retail price at which you sell products on your site, it’s important to remember that the “suggested sell price” is the price at which the product is currently advertised on the Viator site and reflects the current standard industry price for the product. It <u>does not</u> take into consideration the merchant net price (i.e., the price at which you as a merchant partner will be invoiced for the sale) and, in the case of discounting scenarios, may in fact be less than the merchant net price.

Therefore, to ensure that you sell the product at a price which guarantees that you receive at least as much as you will be invoiced for, as well as any extra profit margin that you desire to generate, we recommend you include a check in your implementation that these requirements are satisfied by comparing the suggested retail and merchant net prices and adjusting the retail price at which you advertise the product accordingly.

For example, if the merchant net price for a product is $100, the suggested sell price is $101, and your requirement for a minimum margin is 5%, you should adjust the price at which you advertise the product to $105.

While we recommend that you charge your customers this amount, it is ultimately up to you as to the price you set for the product, bearing in mind that Viator will then invoice you for the merchant net rate (merchantNetPriceFrom) of $555.37 <u>plus</u> a transaction fee calculated as a percentage of the net rate; i.e., the merchant total price.

The exact value of this transaction fee is detailed in your contract with Viator.

Special offers and on-sale pricing

Suppliers have the option of setting special pricing deals for their products. When a product is ‘on sale’; i.e., has a temporarily lowered price, it will be reflected in the product content response, as follows:

Field nameStandard pricingSpecial offer / on-sale pricing
specialOfferAvailablefalsetrue
specialOffer"" (empty string)e.g.: "Book by February 28 to save 10%"
rrp0.0pre-discount price
rrpFormatted"" (empty string)currency-formatted pre-discount price
pricestandard pricespecial offer price
priceFormattedcurrency-formatted standard pricecurrency-formatted special-offer price
merchantNetPriceFromstandard merchant net ratespecial offer merchant net rate
merchantNetPriceFromFormattedcurrency formatted standard merchant net ratecurrency formatted special offer merchant net rate
priceFormattedcurrency-formatted standard pricecurrency-formatted special-offer price
priceFrom (in tourgrades)standard pricespecial offer price
priceFromFormatted (in tourgrades)currency-formatted standard pricecurrency-formatted special-offer price

You can use this information to highlight which products are on special and provide details to the user about the special offer.

Supplier communications

How can suppliers communicate with end customers?

Suppliers occasionally need to reach out to customers for a variety of reasons, such as:

  • Requesting pick-up locations, flight details or passenger weight information
  • Providing weather alerts, sold-out notifications or general messaging

To allow suppliers to contact customers directly, Viator provides a Closed Loop Communication (CLC) system.

How to enable CLC

CLC is enabled per-booking and at the time of booking by supplying the customer’s email and either homePhone or [cellphone + cellPhoneCountryCode] – or both – in the booker object in the request body sent to the /booking/book service when making a booking.

This will allow suppliers to send CLC messages directly to the end customer.

Note:

  • You will receive a CC of each supplier message to your customer support email address in case further assistance is required, but no action from your support team will be necessary for suppliers to communicate with customers.

  • Merchants choosing this option should mention to their customers that they are purchasing a product from a third-party supplier, and that they may therefore receive communications regarding the purchase directly from that supplier.

Example request body snippet to enable direct CLC

{
    ...
    "booker": {
        "homePhone": "(02)66987564",
        "firstname": "Homer Test",
        "surname": "Simpson Test",
        "title": "Mr",
        "cellPhoneCountryCode": "61",
        "cellPhone": "431532778",
        "email": "hsimpson@customeremail.com"
    }
    ...
}

Supplier communications without CLC

To have CLCs from the supplier sent <u>only</u> to your (the merchant’s) customer support team:

  • Leave the cellPhone, cellPhoneCountryCode and homePhone fields blank in the request to the /booking/book service when making a booking.

Note: Utilizing this option requires merchants to manage the final loop of communication with the end customer to ensure that their tour/activity can be fulfilled successfully.

Cancellation policy

As well as making bookings, merchant partners are also able to cancel bookings through the Viator API using the /bookings/cancel-reasons, /bookings/{booking-ref}/cancel-quote and /bookings/{booking-ref}/cancel endpoints. Items cancelled via the /bookings/{booking-ref}/cancel endpoint will be cancelled in full, and only one booking can be cancelled at a time.

For more information about the content of the new merchantTermsAndConditions object, see Cancellation policy.

Cancellation policies

All products can be cancelled by the merchant; however, the refund granted by the supplier to the customer differs depending on the cancellation policy for the product in question.

There are <u>three</u> cancellation policy categories, standard, custom and all sales final, represented by an integer in the merchantTermsAndConditionsType field in the merchantTermsAndConditions object returned by /product: 1, 2 or 3, respectively.

Note: These policies are those provided by Viator to our merchant partners. Merchants can choose whether to extend these terms to their customers unchanged or set their own cancellation terms. For example, the merchant partner can choose to make all products non-refundable; or, they might change the full-refund cancellation window to 72 hours instead of 24 hours, and so forth.

1 – Standard cancellation policy

Products in this category are cancellable up to 24 hours before the travel date (local supplier time) for a full refund. However, a <u>100% cancellation penalty</u> applies for cancellations submitted less than 24 hours before the start time. Most products (about 85%) fall into this category.

Example response snippet

  • Source endpoint: /product
  • Product: 5010SYDNEY
{
  "data": {
    "merchantTermsAndConditions": {
      "termsAndConditions": "For a full refund, cancel at least 24 hours in advance of the start date of the experience.",
      "merchantTermsAndConditionsType": 1,
      "amountRefundable": null,
      "cancellationFromTourDate": [
        {
          "dayRangeMin": 0,
          "dayRangeMax": 1,
          "percentageRefundable": 0,
          "policyStartTimestamp": null,
          "policyEndTimestamp": null
        },
        {
          "dayRangeMin": 1,
          "dayRangeMax": null,
          "percentageRefundable": 100,
          "policyStartTimestamp": null,
          "policyEndTimestamp": null
        }
      ]
    },
    "...": "..."
  }
}

This product has the standard cancellation policy; i.e., when a booking is cancelled:

PolicydayRangeMindayRangeMaxLogicpercentageRefundable
less than <u>one</u> day (24 hours) before the start time01(product_start_time - cancellation_time) >= 0 days && (product_start_time - cancellation_time) < 1 days0
more than <u>one</u> day (24 hours) before the start time1null(product_start_time - cancellation_time) >= 1 day100

2 – Custom cancellation policy

The refund amount for products in this category varies depending on how long before its start time the product is cancelled. Many products on a custom policy are multi-day tours, which require more sophisticated planning on the supplier’s end. Only a small number of products (around 5%) fall into this category.

Example response snippet

  • Source endpoint: /product
  • Product: 2264RJ410
"data": {
  "merchantTermsAndConditions": {
    "termsAndConditions": "If you cancel at least 30 day(s) in advance of the scheduled departure, there is no cancellation fee.&lt;br&gt;If you cancel between 10 and 29 day(s) in advance of the scheduled departure, there is a 50 percent cancellation fee.&lt;br&gt;If you cancel within 9 day(s) of the scheduled departure, there is a 100 percent cancellation fee.&lt;br&gt;",
    "merchantTermsAndConditionsType": 2,
    "amountRefundable": null,
    "cancellationFromTourDate": [
      {
        "dayRangeMin": 10,
        "dayRangeMax": 30,
        "percentageRefundable": 50,
        "policyStartTimestamp": null,
        "policyEndTimestamp": null
      },
      {
        "dayRangeMin": 30,
        "dayRangeMax": null,
        "percentageRefundable": 100,
        "policyStartTimestamp": null,
        "policyEndTimestamp": null
      },
      {
        "dayRangeMin": 0,
        "dayRangeMax": 10,
        "percentageRefundable": 0,
        "policyStartTimestamp": null,
        "policyEndTimestamp": null
      }
    ]
  },
  "...": "..."
}

This product has a complex cancellation policy; where cancellations processed:

PolicydayRangeMindayRangeMaxLogicpercentageRefundable
<u>30</u> days or more before the start time30null(product_start_time - cancellation_time) >= 30 days100
<u>10</u> days and less than <u>30</u> days (10 to 30 days) before the start time or more1030(product_start_time - cancellation_time) >= 10 days && (product_start_time - cancellation_time) < 30 days50
less than <u>10</u> days before the start time010(product_start_time - cancellation_time) < 10 days0

Note: null in the dateRangeMax field means negative infinity; i.e., infinitely far in the past with respect to dateRangeMin.

Additional clauses will be included in the termsAndConditions field in natural language. This field is for human consumption and is not classically machine-interpretable.

3 – All sales final (100% cancellation penalty / no refund offered)

Products in this category cannot be cancelled or amended without incurring a 100% penalty; i.e., the refund amount will be zero. Around 10% of products fall into this category.

Example response snippet

  • Source endpoint: /product
  • Product: 5985P7
{
  "data": {
    "merchantTermsAndConditions": {
      "termsAndConditions": "All sales are final and incur 100% cancellation penalties.&lt;br&gt;",
      "merchantTermsAndConditionsType": 3,
      "amountRefundable": null,
      "cancellationFromTourDate": [
        {
          "dayRangeMin": 0,
          "dayRangeMax": null,
          "percentageRefundable": 0,
          "policyStartTimestamp": null,
          "policyEndTimestamp": null
        }
      ]
    },
    "...": "..."
  }
}

Products in this category can be cancelled, but no refund will be granted (in most cases…)

Canceling items with a ‘pending’ booking status

As alluded, there is an exception to this rule. Products with an ‘on-request’ booking type can still be cancelled when their booking status is "pending" – i.e., before the supplier has confirmed the booking – and a full refund will be granted.

It is impossible to predict how long an ‘on-request’ booking will remain ‘pending’. However, it is possible to check by enquiring about the booking using one of the post-booking services; i.e.:

An ‘all sales final’ product in a ‘pending’ state that can be cancelled and a refund granted will have the following characteristics:

  1. The bookingStatus object returned from one of the services above will have a type of "PENDING", and pending will be true.
  2. The amountRefundable field of the merchantTermsAndConditions object will be non-zero and non-null. Rather, it will contain a currency-formatted string showing the amount that would be refunded if the cancellation were performed immediately; e.g., “USD 55.33”.

Policy start and end times

Within the merchantTermsAndConditions object returned in the response from /booking/book, /booking/pastbooking and /booking/mybookings, the amountRefundable field shows the amount of money in the selected currency that will be refunded if the cancellation is processed now, while the policyStartTimestamp and policyEndTimestamp fields indicate the exact times between which the different cancellation refund rates apply.

Example response snippet (merchantTermsAndConditions) from /booking/book

  • Product: 5010SYDNEY
  • Note: observe that amountRefundable, policyStartTimestamp and policyEndTimestamp are populated here.
"data": {
  "merchantTermsAndConditions": {
    "termsAndConditions": "For a full refund, cancel at least 24 hours in advance of the start date of the experience.",
    "amountRefundable": "USD 55.33",
    "cancellationFromTourDate": [
      {
        "dayRangeMin": 1,
        "dayRangeMax": null,
        "percentageRefundable": 100,
        "policyStartTimestamp": null,
        "policyEndTimestamp": 1551513600000
      },
      {
        "dayRangeMin": 0,
        "dayRangeMax": 1,
        "percentageRefundable": 0,
        "policyStartTimestamp": 1551340800000,
        "policyEndTimestamp": 1551427200000
      }
    ]
  },
  "...": "..."
}

Post-travel cancellations

Occasionally, customers seek a refund for a product after completing their travels.

The reason for this might be because they were unable to attend the tour due to the supplier having cancelled the tour due to bad weather or some other reason out of the customer’s control; or, the customer might have been extremely dissatisfied with the tour itself, felt that it was misrepresented in its advertising, or some other serious complaint.

When this occurs, you will need to send a refund request by email to dpsupport and include both “CANCEL” and the booking reference number in the subject line.

For all post-travel cancellation requests, you will need to include a detailed description of the issue.

Except in cases of known service interruptions (e.g., due to extreme weather events), we will first verify the issue and seek authorization from the product supplier.

Once a decision regarding the refund has been made, we will notify your Customer Services Department with this information. You will then need to advise your customer directly and process the refund if granted.

Interpreting policyStartTimestamp and policyEndTimestamp

The integers that populate the policyStartTimestamp and policyEndTimestamp fields represent points in time that mark the boundaries of the policy time period in the Unix time format; i.e., the number of seconds that have elapsed since 00:00:00 Thursday, 1 January 1970, Coordinated Universal Time (UTC), minus leap seconds.

Unix timestamps can be easily read and interpreted using the ’time’ (or similar) library of your favorite programming language. For human purposes, an online conversion tool can be used.

As per the example above, canceling this booking between the following times yields zero refund (because it is within the 24 hour window):

Field namepolicyStartTimestamppolicyEndTimestamp
Unix time15513408000001551427200000
Human readable timeGMT: Thursday, February 28, 2019 8:00:00 AMGMT: Friday, March 1, 2019 8:00:00 AM
  • Note: Please use policyStartTimestamp and policyEndTimestamp, rather than dayRangeMin and dayRangeMax, to determine which cancellation policy is in effect.

Partial refunds

While we recommend that you, as a merchant partner, support the processing of partial refunds for your customers, it is up to your whether you implement this functionality.

If you would prefer to only grant the full (100%) refund that is offered on most products so long as the cancellation is processed more than 24 hours prior to the product’s start time, we recommend that you implement logic that checks whether a 100% refund is available for the product at the time the customer wishes to cancel their booking.

Type 1: Standard policy (merchantTermsAndConditionsType is 1)
The 100% refund is available so long as the cancellation is performed more than 24 hours prior to the product start time
Type 2: Custom policy (merchantTermsAndConditionsType is 2)
You will need to check whether any of the object-items in the cancellationFromTourDate array have: <ul><li>a percentageRefundable value of 100, and</li><li>dayRangeMin and dayRangeMax or policyStartTimestamp and policyEndTimestamp values that include the present time</li></ul>
Type 3: All sales final (merchantTermsAndConditionsType is 3)
No refunds are available; therefore, granting a refund to your customer for this kind of product will be solely at your expense (i.e., you will still be invoiced for the cost of the tour by Viator). Therefore, we recommend that you do not allow refunds for products with this policy.

Booking references

When a booking is made successfully via the /booking/book endpoint, Viator assigns it a numeric identifier, now known as the booking reference.

This booking reference is returned in the service’s response in the itemId field; however, this itemId is found in different locations depending on the endpoint used:

EndpointitemId element location
/booking/bookdata.itemSummaries[].itemId
/booking/statusdata.itemSummaries[].itemId
/booking/status/itemsdata[].itemId
/booking/pastbookingdata.itemSummaries[].itemId
/booking/mybookingsdata[].itemSummaries[].itemId

The booking reference can used in the request in the following endpoints as the value in the itemId field or in the itemIds array:

New booking references

The new booking cancellation endpoints; i.e.:

…use this booking reference value as an in-URL request parameter, but its format is slightly different.

Essentially, it is the booking’s numeric identifier (itemId), but prepended with BR-. For example, if the itemId is 580254558, the bookingId value in the cancellation request should be BR-580254558.

The booking cancellation endpoints confirm the booking reference in the response in the bookingId field; e.g.:

{
  "bookingId": "BR-580669678",
  "refundDetails": {
    "itemPrice": 412.04,
    "refundAmount": 412.04,
    "refundPercentage": 100,
    "currencyCode": "USD"
  },
  "status": "CANCELLABLE"
}

Common workflows and data validation

Users of the API usually implement a booking process workflow. The common workflows are:

Add to cart

Summary

Because the Viator API is both stateless and does not include services for managing a customer’s shopping cart, this functionality must be fully managed on the merchant’s side.

Viator’s servers can generate a price quote for one or several items, but this collection will not be saved by the server.

We recommend the following process:

  1. View product - allow the customer to browse products and product details
  2. Select date and passengers - allow the customer to check available dates and select the type and number of passengers
  3. Select tourgrade - display the available tour grades
  4. View cart -> price quote - display a total price (including multiple items)

View product

From your view product details section, a button should be presented to check availability or book now or something similar. Use the /product service to retrieve product details and schedules.

Select date and passengers

Here, the customer is presented with the dates that remain available for the product. Available dates can be obtained via a request to /booking/availability/dates. The list of age bands (i.e.: ‘adult’, ‘child’; and, each band’s maximum and minimum age) is available from the /product service.

Validation – ensure that:

  1. The total number of travelers being booked does not exceed the limit returned in the maxTravellerCount field of the /product service
  2. At least one adult (or adult equivalent) passenger has been selected
  3. The selected dates are available (use /booking/availability/dates)

Select tour grade

Once the date and traveler mix have been selected, the customer may need to select a tour grade. Products that do not have this information recorded in the Viator database are assigned a tour grade of "DEFAULT". For these products, it is unnecessary to select a tour grade.

Tour grade options must be displayed to the customer when the product has multiple tour grades, due to:

  • different departure times
  • traveler mix price deals, like family passes
  • different inclusions and prices - e.g., limo pickup, different language delivery options), or…
  • non-default tour grades – these tour grades must be presented to the customer.

The tour grades for a product are retrieved with the /booking/availability/tourgrades service. If a tour grade is available (check the available flag), an ‘add to cart’ button can be displayed. For unavailable tour grades (available is false), a reason (unavailableReason) is provided, which will be one of:

  • "TRAVELLER_MISMATCH"
  • "BLOCKED_OUT", or
  • "UNAVAILABLE"

You may choose to hide the blocked-out tour grades (if all tour grades are unavailable on a particular day, a day’s tour grades are all "BLOCKED_OUT", or the product is not operating that day, the /booking/availability/dates service will not return that date).

You may also find that a product has no bookable tour grades on a day if the traveler mix does not meet that tour grade’s traveler mix restrictions. For example, a honeymoon might require two adults as the only possible traveler mix.

You can choose to hide the "BLOCKED_OUT" tour grades, but you will probably want to display the "TRAVELLER_MISMATCH" grades with the traveler mix requirements listed so that the customer can elect to alter their traveler mix to suit (e.g., for family passes, etc.) You cannot allow the passenger to book with an incompatible traveler mix.

The return object includes information about tour grade restrictions:

ageBandsRequired:

  • minimumCountRequired: minimum number of travelers for an age band
  • maximumCountRequired: maximum number of travelers for an age band. If this field is null, any number of travelers may be booked.

You will need to present the ageBandsRequired information as in the following examples:

In ‘Adult’ age bandMeaning
minimumCountRequired = 1<br>maximumCountRequired = 3From 1 to 3 adults
minimumCountRequired = 0<br>maximumCountRequired = 3up to three adults
minimumCountRequired = 3<br>MaximumCountRequired =3 or more adults
minimumCountRequired = 2<br>MaximumCountRequired = 22 adults

Note: There is a singular and plural version for each age band definition. We recommend automatically generating language that ensures the samples above are grammatically correct using this information.

The user can click back and change their traveler mix; or, they can try selecting another day.

View cart / price quote

Once the item has been added to the cart, you will need to preserve this information as part of the session data in your back-end, or as a browser cookie. In particular, you will need to store the product code and age band to quantity traveler mix.

Sample PHP shopping cart item class

Note: this is only an example and is implementation dependent. Alternatively, you could use the item class (as used in the API calls), but much of the information it contains does not need to be stored:

class shoppingCartItem {
  var $productCode;
  var $tourGrade;
  var $date;
  var $ageBandIdToQty; // assoc array
}

To obtain a price quote, you must call the /booking/calculateprice service. This service requires a currency code and an array of items to be specified. Each item contains the date, product code, tour grade code and an associative array of ageBandIds -> quantity.

Validation – the data must contain valid age bands, tour codes, dates, etc. acquired in previous requests to the API.

Note: A product’s availability can change in the time between API calls as tour grades or products may be blocked out, or the booking window may close for upcoming dates.

Checkout

Summary

The checkout process can be accomplished using the /booking/book service, but you may need to make requests to other services to calculate prices, display product information (age-band names, etc.) and list available pick-up hotels for user selection.

The Viator mobile website breaks the workflow down into three steps. For multiple items, some steps will need to be repeated, such as capturing the traveler names for each tour. In your implementation, you can reorganize/reorder the data collection to better suit your needs.

Example workflow:

  1. Collect traveler details - collect the names of the lead traveler and all other travelers
  2. Collect travel details - ask any additional questions, including those about any special requirements, and select pick-up options.
  • Note: the aforementioned steps will need to be repeated for each item)
  1. Collect booking details
  • Note: billing and payment details should not be sent to Viator.

The classes for the booking request are defined here in Booking Data Classes. You will need implement these in your chosen programming language and verify that the correct JSON objects are generated during serialization.

Traveler details

The traveler details are used to populate the booking-&gt;items[]-&gt;travellers[] objects.

One passenger must be identified as the “lead traveler”. A boolean field in the traveler object represents this flag. The lead traveler must be an adult or have the age band treatAsAdult flag set to true.

All other travelers must be included.

Validation

Ensure that:

  • bandId is a valid age band ID for the product
  • firstname is less than 16 chars
  • surname is less than 36 chars
  • title is not included unnecessarily (it is optional)
  • leadTraveller is set to true for one of the travelers who is in an age band that has the treatAsAdult flag set to true

Other details

Booking questions

The travel details include the booking questions that are supplied in the /product service.

Sample question

Note: There may be more than one.

bookingQuestions: [{
  "message": "For safety reasons you must enter the weight of &lt;b&gt;all&lt;/b&gt; passengers",
  "required": true,
  "questionId": 23,
  "title": "Passenger Weights",
  "subTitle": "(e.g. 127 pounds, 145 kilos, etc)",
  "sortOrder": 1
}]

The questions should be displayed with the title, message, subtitle and whether it is mandatory (required) or not.

Validation – if the question is mandatory, the user must enter at least one character.

Special requirements

‘Special requirements’ should be presented as a text input field so that customers can record whether they require wheelchair assistance, for example. It is not mandatory for the customer to enter any text.

Pick-up information

The last thing that must be collected for each item being booked is the pick-up information. If the product includes pick-up, the hotelPickup flag will be set to true (in the product object).

If pick-up is included, you will need to make a request to /booking/hotels to determine if a hotel list exists. If it does, the list must be displayed so that the customer can make their selection. If not, a text input field should be displayed for hotel name collection.

Please note that the first three results in the list are not hotels; rather, these three are alternative selections, comprising:

  • ‘Hotel not listed’
  • ‘Live locally or staying with family/friends’
  • ‘Hotel not yet booked’

If the customer selects ‘hotel not listed’, you must provide a hotel selection text input field. For the other two options, no hotel name is required. In all cases, the hotel ID must be updated with either a hotel ID or the IDs of the three items listed.

If no hotel list is available, you must provide a text input field for collecting the customer’s hotel name. Please include instructions to enter ’live locally’ or ‘hotel not yet booked’ if they cannot provide a hotel name.

Validation – if hotel list is available, the hotelId must be supplied. If the hotelId is notListed the, pickupPoint field must have at least one character.

If a hotel list is not available, then pickupPoint must contain a value.

Language services

If the response from the /product service contains information in the languageServices field, e.g.:

"langServices": {
  "en/SERVICE_AUDIO": "English - Audio"
}

…you must specify which language option you wish to book for this tour in the languageOptionCode field (see request body schema of the /booking/book service).

View voucher or confirmation status

The object returned by the /booking/book service contains booking details that can be used to display an order summary to the customer.

Confirmed bookings of freesale products will return a voucherKey and voucherURL. The voucherURL is accessible by the customer to view their voucher.

Pending bookings of on-request products will return null in the voucherKey/voucherURL fields. These fields will only contain values once the booking is confirmed.

A bookingStatus object is included in the response that contains the status of the booking.

"bookingStatus": {
  "status": 1,
  "text": "Paid &amp;amp; Confirmed",
  "type": "CONFIRMED",
  "level": "ITEM",
  "failed": false,
  "confirmed": true,
  "amended": false,
  "pending": false,
  "cancelled": false
}

The status field corresponds to a number described in bookingStatus field values and meanings.

Boolean flags that you can inspect to determine the booking status of the item:

  • failed
  • cancelled
  • confirmed
  • amended
  • pending

Pending bookings

A booking is considered pending if the booking process is ‘in progress’. For example, an on-request booking would be pending until it is confirmed/rejected by the supplier.

If a customer has made an amendment to an on-request booking that is yet to be accepted by the supplier, the booking would then have a status of amended when the supplier or customer service accepts the amendment.

Example response object:

{
  "errorReference": null,
  "data": {
    "sortOrder": 0,
    "rulesApplied": [],
    "bookingStatus": {
      "status": 3,
      "text": "Confirmed",
      "type": "CONFIRMED",
      "level": "ITINERARY",
      "confirmed": true,
      "pending": false,
      "amended": false,
      "cancelled": false,
      "failed": false
    },
    "itemSummaries": [{
      "sortOrder": 0,
      "rulesApplied": [],
      "bookingStatus": {
        "status": 1,
        "text": "Paid &amp;amp; Confirmed",
        "type": "CONFIRMED",
        "level": "ITEM",
        "pending": false,
        "failed": false,
        "confirmed": true,
        "amended": false,
        "cancelled": false
      },
      "travellerAgeBands": [{
        "sortOrder": 0,
        "count": 1,
        "pluralDescription": "Adults",
        "description": "Adult",
        "ageBandId": 1
      }],
      "voucherKey": "1005851866:4af44c13ecf3f1a7d3f9ef2fc00c2257e08fa42ae20f877f3039ff9b52aba24e:580669678",
      "voucherURL": "https://viatorapi.live.rc.viator.com/service/merchant/voucher.jspa?code=1005851866:4af44c13ecf3f1a7d3f9ef2fc00c2257e08fa42ae20f877f3039ff9b52aba24e:580669678&amp;embedResources=false",
      "voucherRequirements": "You must present a paper voucher for this to",
      "productPulledDown": false,
      "merchantCancellable": true,
      "productWidgetList": null,
      "savingAmount": 0,
      "passbooks": null,
      "termsAndConditions": null,
      "itineraryId": 1000024753,
      "tourGradeCode": "1DAYBOAT",
      "productCode": "2065CPT",
      "leadTravellerSurname": "Test",
      "distributorItemRef": "distroItemRefJDP1803151135",
      "languageServicesLanguageCode": "en",
      "travelDate": "2016-02-01",
      "price": 3.72,
      "bookingEngineId": "UF",
      "merchantNetPrice": 3.51,
      "merchantNetPriceFormatted": "$3.51",
      "leadTravellerTitle": "Mr",
      "leadTravellerFirstname": "Homer",
      "lastRetailPrice": 3.51,
      "destId": 318,
      "voucherOption": "VOUCHER_PAPER_ONLY",
      "productTitle": "Cape Town City Hop-on Hop-off Tour",
      "itemId": 700025496,
      "barcodeOption": "perperson",
      "barcodeType": "code128",
      "obfsId": 3696,
      "priceFormatted": "$3.72",
      "savingAmountFormated": "",
      "priceUSD": 3.72,
      "lastRetailPriceFormatted": "$3.51",
      "departsFrom": "Cape Town, South Africa",
      "hoursConfirmed": 0,
      "currencyCode": "USD"
    }],
    "voucherKey": "1005851866:4af44c13ecf3f1a7d3f9ef2fc00c2257e08fa42ae20f877f3039ff9b52aba24e:580669678",
    "voucherURL": "https://viatorapi.live.rc.viator.com/service/merchant/voucher.jspa?code=1005851866:4af44c13ecf3f1a7d3f9ef2fc00c2257e08fa42ae20f877f3039ff9b52aba24e:580669678&amp;embedResources=false",
    "bookerEmail": "apitest@viator.com",
    "userId": null,
    "itineraryId": 1000024753,
    "exchangeRate": 1,
    "totalPriceFormatted": "$3.51",
    "totalPriceUSD": 3.51,
    "bookingDate": "2015-03-17",
    "distributorRef": "distroRefJDP1803151135",
    "totalPrice": 3.51,
    "hasVoucher": true,
    "currencyCode": "USD"
  },
  "dateStamp": "2015-03-17T17:36:32+0000",
  "errorType": null,
  "errorMessage": null,
  "errorName": null,
  "success": true,
  "totalCount": 1,
  "vmid": "321003",
  "errorMessageText": null
}

Checking the status of bookings

Checking the status of a single booking:

  • /booking/mybookings can be used to check the status of a booking after it has been purchased. This is useful for checking the status of a pending booking, particularly if there are multiple items within the booking.

    It is recommended that you poll the service no more than once per hour.

Checking the status of multiple bookings:

  • /booking/status will return the status of all bookings, based on the following:
    • booking date range
    • travel date range
    • specific distributor/distributor item references
    • lead traveler date/first name

This is useful for checking the status of recently-made, but still pending bookings, or those that will commence soon.

Note: You can only poll this service (successful calls) once every 30 minutes.

Confirming the booking via email

Upon receiving a successful response from /booking/book, merchant partners should confirm the booking with the customer via email. This email must be sent by the merchant partner (not Viator).

Sample confirmation email

<pre> Dear Traveller,

Thank you for booking with [PARTNER NAME] on [www.domain.com]. Your booking is confirmed. This is your booking notification and receipt. Please retain this email for your records.

Please note:

We offer three types of vouchers. Be sure to check below for what type of voucher your tour / activity requires. Voucher requirements vary by tour, so if you’ve booked more than one tour, be sure to check each one. See below for instructions.

HOTEL/FLIGHT ITINERARY

[Your standard reply here]

TOURS

  1. Name: Whale Watching Cruise e-Voucher or Paper Voucher Accepted You can present either a paper or an electronic voucher for this activity. Voucher: [VOUCHERURL] Please click on the above link, follow the directions, and print your voucher to present as per instructions on the voucher under ‘Important Information’.
  2. Name: Boston City Pass Paper Voucher Required You must present a paper voucher for this tour. Voucher: [VOUCHERURL] Please click on the above link, follow the directions, and print your voucher to present as per instructions on the voucher under ‘Important Information’.
  3. Name: SuperShuttle Airport Transfer Voucher Not Required You must present a paper voucher for this tour. Voucher: [VOUCHERURL] You can present a paper or electronic voucher for this activity, or you can simply present the Lead Traveller’s Photo ID. Our supplier has your reservation on file and only requires proof of identity on the day of travel.

IMPORTANT INFORMATION

[Your standard reply here]

TERMS AND CONDITIONS

[Your standard reply here] </pre>

Booking process flow

In this section, we show a sample booking process flow using Viator API services.

Search for a product

  1. Determine the destinationId for the desired destination using the /taxonomy/destinations service.
  2. Search for products in the destination with the /search/products service using the destinationId, along with optional parameters like the date range (startDate and endDate), attraction link (seoId), category (catId) and subcategory (subCatId).

Example /search/products POST request body:

{
  "startDate": "2018-12-25",
  "endDate": "2018-12-28",
  "topX": "1-15", 
  "destId": 684, 
  "currencyCode": "USD",
  "sortOrder": "TOP_SELLERS"
}

Note: the startDate and endDate must be in the future.

  1. Get the product details with the /product service.

Example parameters for a /product GET request:

code=5010SYDNEY&amp;currencyCode=USD

Determine the product’s available dates

Use the /booking/availability/dates service to retrieve a list of dates on which the product is operating. This list can be used to populate a calendar display of available dates.

Example parameters for an availability check using the /booking/availability/dates service:

productCode=5010SYDNEY

Determine the available age bands for the product

Because the product option (tour grade) availability check requires the desired passenger mix, the user will first need to select the number of travelers and the age band into which each can be classified.

Note: The exact ages to which each age band refers to differs between products. See Working with age bands for more information.

  1. Determine the number of passengers/travelers (and their respective agebands) by having the user input the passenger mix for which they wish to make a booking.
  2. Check for available tour grades for the date chosen using the /booking/availability/tourgrades service; or, check for available tour grades by month using the /booking/availability/tourgrades/pricingmatrix service

/booking/availability/tourgrades POST request:

{
  "productCode": "5010SYDNEY",
  "bookingDate": "2018-12-05",
  "currencyCode": "USD",
  "ageBands": [
    {      
      "bandId": 1,
      "count": 2    
    }  
  ]
}

/booking/availability/tourgrades/pricingmatrix POST request:

{
  "productCode": "5010SYDNEY",
  "month": "12",
  "year": "2018",
  "currencyCode": "USD"
}
  1. Finalize pricing using the /booking/availability/tourgrades/pricingmatrix service.
  • Note: we strongly recommend using the /booking/calculateprice service prior to making the booking, as it reconfirms the product availability for the specified dates and passenger mix.
  1. Make the booking
  • Note that the /booking/book service supports multi-item bookings. The response from the /product service indicates mandatory information that must be sent when making the booking, such as required booking questions and hotel pick-up options.
  • For hotel pick-up:
    • Send a hotel ID to the /booking/book service if hotelPickup is true for the product.
    • /booking/hotels can be used to return a list of hotels available for the product.
    • The hotelId is the id field in the response from the /booking/hotels service. This can be:
      • a number (represented as a string) – e.g., '4119'
      • 'local' – if the customer resides near the location in which the product operates
      • 'notBooked' – if the customer’s hotel is not yet booked
      • 'notListed' – if the customer’s hotel is not listed in the response from /booking/hotels. If this is the case, capture the customer’s hotel details in a text box and pass this information in the pickupPoint field in the request body of the /booking/book service.

/booking/book POST request example:

{
  "demo": true,
  "currencyCode": "USD",
  "partnerDetail": {
      "distributorRef": "distributorRef1550616101308"
  },
  "booker": {
      "firstname": "Homer Test",
      "surname": "Simpson Test",
      "title": "Mr",
      "email": "apitest@viator.com",
      "homePhone": "(02)66987564"
  },
  "items": [
    {
      "partnerItemDetail": {
        "distributorItemRef": "distributorItemRef1550616101308"
      },
      "hotelId": null,
      "pickupPoint": null,
      "travelDate": "2019-03-19",
      "productCode": "5010SYDNEY",
      "tourGradeCode": "24HOUR",
      "languageOptionCode": "en/SERVICE_GUIDE",
      "bookingQuestionAnswers": [
        {
          "questionId": 100,
          "answer": "120 kgs"
        }
      ],
      "specialRequirements": "",
      "travellers": [
        {
          "bandId":1,
          "firstname": "Homer",
          "surname": "Simpson Test",
          "title": "Mr",
          "leadTraveller": true
        }, {
          "bandId": 1,
          "firstname": "Marge",
          "surname": "Merchant Viator Test",
          "title": "Mrs"
        }
      ]
    }
  ]
}

/booking/hotels GET example parameters:

productCode=5010SYDNEY

or

destId=684
  1. You will receive different booking statuses depending on the product’s booking engine.
  • For products that are free-sale ('FreesaleBE'), unconditional free-sale ('UnconditionalBE') and free-sale / on-request ('FreesaleOnRequestBE') - i.e., during the free-sale period, confirmation should occur instantly.
  • The 'FreesaleOnRequestBE' status means that the product will only remain free-sale up until a certain number of days before the travel date, after which it becomes on-request.
  • Normally, if the product is on-request, its booking status will be 'Pending'.

Post-booking

Displaying vouchers

To display the voucher to your customer, direct them to the URL returned in the voucherURL field in the response from the /booking/book service.

Note: the voucher will not be available until the booking is confirmed – the value of the hoursConfirmed field in the response from the /booking/book service can be shown to the customer to indicate the time frame within which they are likely to be notified as to their booking confirmation.

Viewing bookings

Viewing booking statuses

To view the booking statuses for multiple items based on various criteria, use the /booking/status service.

Note that this service can only be polled once every five minutes. Ideally, this service should be used by your software implementation to perform bulk updates of pending itineraries. The maximum number of itinerary results returned is 1,000.

merchantNetPrice and price in the /search/products service

The difference between these fields is as follows:

  • merchantNetPrice is the amount you, as the merchant partner will be invoiced for, excluding any fees.
  • price is the price at which Viator sells the product

Note: these prices are also returned (per age band) by the following services:

Currency considerations for bookings

If the booking shows prices converted to and formatted according to a different currency to that in which it was made, it is because each API partner has a particular ‘base currency’, and all bookings will be made in that currency.

Booking and transaction fees

The total price may be different to the merchantNetPrice due to the fact that a booking fee – i.e., a transaction fee or commission – is added to all bookings.

This fee is a fixed percentage with a capped maximum. The exact percentage depends on your merchant partner agreement with Viator and can be found in your contract with Viator.

Making demo bookings

To make a demo booking, simply set the demo field to true in the /booking/book service.

While demo bookings are allowed on the live production environment, we recommend not doing so as it is possible that a notification could be sent to the supplier. Performing a cancellation of the demo booking is therefore recommended.

To cancel the booking, partners should use the /bookings/{id}/cancel service. For details on canceling a booking, see: Cancellation API workflow

Cancellation UX

On the Viator.com website, once the customer has made a booking, they are able to access the details of all their upcoming, past and cancelled bookings by navigating to the bookings section of the website.

You must communicate to the user the terms and conditions that pertain to canceling their booking; i.e., what to expect in terms of the refund they will receive if they were to cancel their booking now.

On the Viator website, this information is communicated in the cancellation button text. In the following example, the user has booked the “San Francisco City Tour with Alcatraz”, and is viewing their bookings page.

In this way, the user is told that they can “cancel for free by Oct 22” – i.e., they will be issued a full refund if they cancel the product prior to October 22:

user bookings

This text is programmatically generated by inspecting the product’s cancellation policy, which is contained within the merchantTermsAndConditions object, which is included in the response object from the following endpoints:

For details on how to interpret the merchantTermsAndConditions object, see: Cancellation policy

Once the user clicks the button labelled: Cancel for free by Oct 22, they are brought to the cancellation confirmation page, where they are provided a more formal cancellation quote prior to confirming their intention to cancel the product.

Cancellation refund display

As the merchant of record, the amount your customer was charged for the product was your decision; therefore, the amount that you elect to grant the customer as a refund is also up to you, so you will need to retrieve the amount the customer has paid for the product from your own records/databases.

The amount that Viator would have invoiced you for the booking – equivalent to the merchant net price at the time of booking plus the transaction fee – can be retrieved using the /bookings/{booking-ref}/cancel-quote endpoint. For more information see: Get a cancellation quote

Here, the customer is shown that they will receive a full refund if they cancel the product now:

cancellation quote

Displaying and choosing cancellation reasons

At this point in the workflow, the user must select a reason for their cancellation. Viator’s systems require that a reason for the cancellation be given in order to carry out the cancellation process.

As the set of acceptable reasons for canceling a booking are formally specified by the Viator Partner API and are not necessarily immutable (new reasons may be added at any time) you should retrieve the presently available cancellation reasons from the /bookings/cancel-reasons endpoint. We require you to present these to the customer for them to select.

Use the cancellationReasonText fields in the response to populate the list from which the customer can select the most-appropriate match for why they are canceling, as on the Viator website:

user bookings

For more information about getting cancellation reasons, see: Getting cancellation reasons

Note: As it is necessary for the user to provide a cancellation reason, it is required that the Cancel Booking button remain disabled until a reason has been selected by the customer.

Completing the cancellation

Once the user has selected a reason, the Cancel Booking button can be activated:

cancel booking

Clicking the Cancel Booking button is the final action required of the customer to complete the cancellation.

At this point, you will want to cancel the booking using the /bookings/{booking-ref}/cancel API endpoint. For more information on using this service, see: Cancel the booking

Obtaining confirmation for the cancellation

On the Viator.com site, the following confirmation message is displayed on the page that loads after the Cancel Booking button is clicked:

cancellation confirmation

Cancellation confirmation email

Once the cancellation is accepted, a short, succinct email informing the customer that their booking has been successfully canceled is sent immediately:

cancellation confirmation email

Viewing canceled bookings

Clicking on the View reservation details button in the cancellation confirmation email returns the customer to their bookings page, where the fact of the booking being canceled is communicated clearly:

canceled booking

Cancellation API workflow

Note:

Getting cancellation reasons

<a id=“getting-cancellation-reasons”></a>

When canceling a booking, you are required to submit a valid ‘reason for the cancellation’ to assist with Viator’s internal processes. This is accomplished via the inclusion of a valid reason code in the body of the request. The reason codes can be retrieved from the /bookings/cancel-reasons endpoint.

As the acceptable reasons for cancellation may be extended at any point (existing reasons will not change or be removed), we recommend retrieving an up-to-date list from this endpoint at least weekly.

The output from the /bookings/cancel-reasons endpoint at the time of writing is as follows:

{
    "reasons": [
        {
            "cancellationReasonCode": "Customer_Service.I_canceled_my_entire_trip",
            "cancellationReasonText": "I canceled my entire trip"
        },
        {
            "cancellationReasonCode": "Customer_Service.Booked_wrong_tour_date",
            "cancellationReasonText": "Booked wrong tour/date"
        },
        {
            "cancellationReasonCode": "Customer_Service.Duplicate_Booking",
            "cancellationReasonText": "Duplicate Booking"
        },
        {
            "cancellationReasonCode": "Customer_Service.Chose_a_different_cheaper_tour",
            "cancellationReasonText": "Chose a different/cheaper tour"
        },
        {
            "cancellationReasonCode": "Customer_Service.Weather",
            "cancellationReasonText": "Weather"
        },
        {
            "cancellationReasonCode": "Customer_Service.Unexpected_medical_circumstances",
            "cancellationReasonText": "Unexpected/medical circumstances"
        },
        {
            "cancellationReasonCode": "Customer_Service.Tour operator asked me to cancel",
            "cancellationReasonText": "Tour operator asked me to cancel"
        }
    ]
}

Canceling a booking

Getting a cancellation quote

<a id=“get-a-booking-cancellation-quote”></a>

Before canceling the booking, call the /bookings/{booking-reference}/cancel-quote endpoint to get information about whether the booking can be canceled using this endpoint and what the refund will be, for example:

GET https://api.viator.com/partner/bookings/BR-580254558/cancel-quote

Note: For information about the {booking-reference} in URL parameter, see Key concepts: Booking references

You will receive a cancellation quote object, e.g.:

{
    "bookingId": "BR-580254558",
    "status": "CANCELLABLE",
    "refundDetails": {
        "itemPrice": 109.77,
        "refundAmount": 109.77,
        "currencyCode": "USD",
        "refundPercentage": 100.00
    }
}

Note: Bookings that have not been confirmed by the supplier and have a status of "PENDING" will report an itemPrice, refundAmount and refundPercentage of 0, as no fees are charged until the booking’s status is "CONFIRMED".

The data elements in this object have meanings as follows:

ElementMeaningExample
bookingIdthe booking reference number prepended with BR-BR-580254556
statusOne of the following: <ul><li>CANCELLABLE: the booking is eligible to be cancelled</li><li>CANCELLED: the booking has already been cancelled</li><li>NOT_CANCELLABLE: the booking is for a product that operated in the past, and therefore cannot be cancelled using this endpoint (you will need to send an email to dpsupport including both “CANCEL” and the booking reference number in the subject line in order to request a refund for such a booking)</li></ul>CANCELLABLE
refundDetailsobject containing information about the refund
itemPricethe merchant net price + transaction fee for this product at the time of booking in the currency specified by currencyCode109.77
refundAmountthe amount that will be deducted from your invoice if the booking is cancelled now109.77
currencyCodethe currency code for the currency in which pricing information is displayedUSD
refundPercentagethe refund amount expressed as a percentage of the itemPrice100.00

Canceling the booking

<a id=“cancel-the-booking”></a>

If the status field has a value of CANCELLABLE and you are happy with the refundAmount, call the /bookings/{booking-ref}/cancel endpoint to cancel the booking, e.g.:

POST https://api.viator.com/partner/bookings/BR-580254558/cancel

A reason code corresponding to the reason for cancellation must be included in the request body; e.g.:

{
  "reasonCode":"Customer_Service.Chose_a_different_cheaper_tour"
}

You should receive a response indicating that the cancellation was successful, e.g.:

{
    "bookingId": "BR-580254558",
    "status": "ACCEPTED"
}

A status of ACCEPTED indicates that the booking was successfully canceled.

Calculating prices

The /booking/calculateprice service is used to calculate a total price for one or more products, with the ability to specify the date and passenger mix for each product individually.

It also reconfirms the availability and pricing of the products for the requested dates and passenger mixes. We strongly recommended that you call this service prior to making a booking to establish that the booking will succeed once submitted.

This endpoint is useful when implementing a shopping cart, as multiple product bookings can be enquired about in a single call to this service.

Example request body (JSON)

{
  "currencyCode": "USD",
  "items": [{
    "travelDate": "2015-03-01",
    "productCode": "2916ROME",
    "tourGradeCode":"24HR",
    "travellers": [
      {
        "bandId": 1
      },
      {
        "bandId": 1
      }
    ]
  }]
}

The quirky travellers array is used to specify the number of travellers in each age band. Each member object of this array corresponds to a single traveller. The example above signifies “two adults from bandId: 1”.

Another example might be “three travelers from bandId:1 and two travelers from bandId:2”. That would be as follows:

"travellers": [
  {
    "bandId": 1
  },
  {
    "bandId": 1
  },
  {
    "bandId": 1
  },
  {
    "bandId": 2
  },
  {
    "bandId": 2
  }
]

Price information

The total price (i.e., including the transaction fee) that you will be invoiced for the products to be booked is given in the following fields in the response from this service:

  • data.itemSummaries[].price (numeric total price of item)
  • data.itemSummaries[].priceFormatted (currency formatted total price of item)
  • data.itinerary.totalPrice (numeric total price of item)
  • data.itinerary.totalPriceFormatted (currency-formatted total price of item)

For more information about pricing fields and their meaning throughout this API, see: Merchant pricing.

Determining whether the product is ‘freesale’ or ‘on request’

You can determine whether the booking is freesale or on-request by examining the response from this endpoint. ‘Freesale’ bookings are those that are confirmed immediately (with a status of "CONFIRMED") when booked, while on-request bookings are instead confirmed by the supplier at a later time.

The approximate time window for confirmation is provided in the hoursConfirmed (integer) field. This can be presented to the customer.

  • An hoursConfirmed of 0 means that the booking is freesale.
  • An hoursConfirmed greater than 0 indicates that the booking is on-request.

Finding hotel pick-up points

Hotel pickup example:

Example response body (/booking/hotels)

{
  "vmid":"221002",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2012-04-12T13:48:27+0000",
  "success": true,
  "errorReference": null,
  "errorMessageText": null,
  "totalCount": 1,
  "errorName": null
  "data": [
    {
      "address": null,
      "name": "I live locally / I'm staying with friends, relatives",
      "id": "local",
      "phone": null,
      "productCodes": null,
      "destinationId": 0,
      "city": null,
      "notes": null,
      "latitude": null,
      "longitude": null,
      "postcode": null,
      "brand": null,
      "hotelString": "I live locally / I'm staying with friends, relatives",
      "sortOrder": 1
    },
    {
      "address": null,
      "name": "My hotel is not yet booked",
      "id": "notBooked",
      "phone": null,
      "productCodes": null,
      "destinationId": 0,
      "city": null,
      "notes": null,
      "latitude": null,
      "longitude": null,
      "postcode": null,
      "brand": null,
      "hotelString": "My hotel is not yet booked",
      "sortOrder": 2
    },
    {
      "address": null,
      "name": "My hotel is not listed",
      "id": "notListed",
      "phone": null,
      "productCodes": null,
      "destinationId": 0,
      "city": null,
      "notes": null,
      "latitude": null,
      "longitude": null,
      "postcode": null,
      "brand": null,
      "hotelString": "My hotel is not listed",
      "sortOrder": 3
    },
    {
      "address": "375 East Harmon Avenue",
      "name": "Alexis Park Resort Hotel",
      "id": "684_2",
      "phone": "",
      "productCodes": null,
      "destinationId": 684,
      "city": "Las Vegas",
      "notes": null,
      "latitude": 36.106258,
      "longitude": -115.156146,
      "postcode": "89169",
      "brand": "",
      "hotelString": null,
      "sortOrder": 4
    },
    {
      "address": "167 East Tropicana Avenue",
      "name": "Americas Best Value Inn",
      "id": "684_3",
      "phone": "",
      "productCodes": null,
      "destinationId": 684,
      "city": "Las Vegas",
      "notes": null,
      "latitude": 36.100778,
      "longitude": -115.165522,
      "postcode": "89109",
      "brand": "",
      "hotelString": null,
      "sortOrder": 5
    },
    {
      "address": "3131 Las Vegas Boulevard South",
      "name": "Wynn Resort",
      "id": "684_126",
      "phone": "",
      "productCodes": null,
      "destinationId": 684,
      "city": "Las Vegas",
      "notes": null,
      "latitude": 36.127563,
      "longitude": -115.167704,
      "postcode": "89109",
      "brand": "",
      "hotelString": null,
      "sortOrder": 119
    }
  ]
}

Making a booking

To make a booking, use the /booking/book service.

To make a real booking, ensure demo is set to false in the booking request.

Demo bookings will enter our system as a test booking and will not charge the merchant. To enable demo bookings, set demo to true in the booking request and pass "test" as the traveler’s first or last name.

Note: Avoid testing on Live, as the booking may be sent to the supplier (depending on the product). Any test bookings on live must be cancelled via the /bookings/{id}/cancel service; or, contact dpsupport@viator.com if you experience any other issues.

distrbutorRef and distributorItemRef

The distributorRef and distrbutorItemRef fields are the merchant partner’s own reference for the booking. All merchant partners must pass a distributorRef and a distributorItemRef in all bookings.

It can be any alphanumeric string, and in for the distrbutorRef, it must be unique to bookings made by the merchant.

If an existing distributorRef is passed, the booking with the matching distributorRef will be returned in the response, and a new booking will not be made.

Please see the description for these fields in the table below for more information.

Example request

{
  "demo": true,
  "currencyCode": "USD",
  "partnerDetail": {
    "distributorRef": "distroRef0412141435"
  },
  "booker": {
    "email": "apitest@viator.com",
    "firstname": "Homer Test",
    "surname": "Simpson Test",
    "title": "Mr"
  },
  "items": [{
    "partnerItemDetail": {
      "distributorItemRef": "distroItemRef0412141435_1"
    },
    "hotelId": null,
    "pickupPoint": null,
    "travelDate": "2015-03-31",
    "productCode": "2916ROME",
    "tourGradeCode": "24HR",
    "languageOptionCode": "en/SERVICE_GUIDE",
    "bookingQuestionAnswers": [{
      "questionId": 100,
      "answer": "120 kgs"
    }],
    "specialRequirements": "",
    "travellers": [{
      "bandId": 1,
      "firstname": "Homer",
      "surname": "Simpson Test",
      "title": "Mr",
      "leadTraveller": true
    }]
  }]
}

Description of JSON request parameters

Object nameElement nameTypeCommentsMandatory
demobooleanIf this is set to True, then it is a demo booking only. Full demos do not send any notifications, are automatically confirmed and OnRequest products become freesale products. Default value is true. Production must have demo set to false.
currencyCodestringThe currency the booking will be submitted in. You will be billed in this currency.
partnerDetailobjectApplicable only for extra partner detail for either partner or merchant partner for sending partner specific information
distributorRefstringMerchant API partners must pass a distributorRef at itinerary level in the partnerDetails object. The distributorRef passed must be alphanumeric and unique to bookings made by the merchant. Passing an existing distributorRef: If an existing distributorRef is passed, the booking with the matching distributorRef will be returned in the response and a new booking will not be made. The fields in the response are identical to the response for a new booking.
partnerItemDetailobjectFor extra partner detail at an item level, for either partner or merchant partner.
distributorItemRefstringMerchant API partners must pass a distributorItemRef into the partnerItemDetails object for each item in the items object. The distributorItemRef passed must be alphanumeric and unique to the itinerary.
bookerobjectThe information of the primary contact. This contact does not have to be a traveler.
emailstringEmail address of the primary contact
homePhonestringHome phone number of the primary contact
firstnamestringFirst name of the primary contact
surnamestringSurname of the primary contact
titlestringTitle of the primary contact
itemsArray of items in itinerary to be booked
productCodestringproduct code of the itinerary to be booked
tourGradeCodestringtourGradeCode of the item to be booked. If tour grades are supplied in /product, you must allow the customer to select a tour grade code. If no tour grades are available for the product, pass "DEFAULT".
languageOptionCodestringThe language service provided for this product that has been chosen for this booking. Usually in the format langcode/Service eg "en/SERVICE_GUIDE". If the product details service /product for the product returns a langService, this must be provided.✅<br />(if languageServices are provided in /product)
travelDatedatedate of travel for the item (format is YYYY-MM-DD; e.g. 2013-12-25)
hotelIdstringIf /product returns hotelPickup: true and a list of hotels is available for this product in /booking/hotels, a hotelId must be captured. The hotel id as per the hotel service (id field) or use one of these alternative hotel ids:<br />local: customer lives locally<br />notBooked: Customer has not booked their hotel yet<br />notListed: Hotel not listed✅<br />(if /product returns hotelPickup: true for productCode and hotels available)
pickupPointstringPickup point information related to hotel pickup. Details of the hotel or pickup point must be provided if the hotelId selected by the user is "notListed" or if no hotels are returned for the product in /booking/hotels where hotelPickup: true✅<br />(if hotelId = "notListed" or no hotels returned)
specialRequirementsstringCapture any additional requirements for the booking, such as dietary requirements or if a wheelchair is required. Suggested workflow is if there are no bookingQuestionAnswers for the product, to collect specialRequirements.
travellersArray of traveller names with a required lead traveller selected per item.
bandIdintegerAge band id. Available age band details for the product is listed in /product.
firstnamestringFirst name of the traveller
surnamestringSurname of the traveller
titlestringTitle of the traveller. Suggested options: Mr, Mrs, Ms, Miss, Mstr, Dr
leadTravellerbooleanEach item must have one traveller assigned as the lead traveller for the tour. The lead traveller will have a value of true, all other travellers will have a value of false. The lead traveller can have a mobile phone number added to the booking.
cellPhoneCountryCodestringIdeally only collect the phone number country code for the lead traveller. Alternatively, collect the phone number of the booker instead.
cellPhonestringIdeally only collect the phone number country code for the lead traveller. Alternatively, collect the phone number of the booker instead.
bookingQuestionAnswersobjectAnswers to booking questions for the particular item. If a booking question is available in the bookingQuestions array in /product for the product, the matching bookingQuestionAnswers must be passed. If a product does not have any bookingQuestion items, you can omit the bookingQuestionAnswers field completely. Any invalid or unnecessary bookingQuestionAnswers that are passed to /booking/book will be ignored (no exceptions will be raised)✅<br />(if /product returns bookingQuestions)
questionIdintegerquestionId (provided in /product)
answerstringAnswer to the question at the questionId listed. Recommended length for the answer is 500 characters.

JSON Response

The prices returned in the booking response represent the net rate, which is the amount merchant API partners will be invoiced for. See merchant pricing for more information.

Booking errors

A number of errors may be returned in the response to the /booking/book service. If any errors are reported, NO items will be booked, NO items/data will be returned in the response, and NO billing will occur.

There are two error types:

  • "VALIDATION" - occurs if a required field is missing or a field is not formatted properly
  • "EXCEPTION" - occurs when there are issues with the booking date, product / tour grade code or the payment.

Example of an error message:

{
  "data": null,
  "vmid": "221001",
  "errorMessage": [ "Missing distributor reference" ],
  "errorType": "EXCEPTION",
  "dateStamp": "2013-04-24T15:50:05+0000",
  "errorReference": "~3713624959841553334512668",
  "errorMessageText": ["Missing distributor reference" ],
  "success": false,
  "totalCount": 1,
  "errorName": "Exception"
}

Please see “Standard JSON fields” in the Appendix for an explanation of the fields.

ScenarioerrorTypeExample error message text
Lead traveller is not specifiedVALIDATIONA traveler needs to be selected as lead traveler. Lead Traveler’s name must match credit card name.
Traveller names are not providedVALIDATIONFirst name of traveler 1 is required, Last name of traveler 1 is required
No travellers providedVALIDATIONA traveler needs to be selected as lead traveler. Lead Traveler’s name must match credit card name.
Product code does not existEXCEPTIONWe’re sorry, we cannot find the tour, activity or attraction you are looking for
Product code exists, but tour grade code does not existEXCEPTIONSICInvalidTourGrade
Booking date is in the pastEXCEPTIONWe’re sorry, the following tour you are trying to book is sold out and no longer available: Grand Canyon All American Helicopter Tour (2280AAHT)
languageOptionCode is in the wrong formatEXCEPTIONlanguageOptionCode should be LangCode/LangServices
Missing required answers for itemEXCEPTIONAdditional questions missing
Unsupported currencyEXCEPTIONCould not lookup SGD:java.lang.RuntimeException: Could not lookup SGDf:au.com.fim.v3.etravel.PiusRecordNotFoundException: No currency found: select * from CurrencyFormat where currencyID = ‘SGD’
distributorRef not provided in partnerDetail objectEXCEPTIONMissing distributor reference
distributorItemRef not provided in partnerItemDetail objectEXCEPTIONMissing distributor item reference
partnerItemDetail object not provided for the itemEXCEPTIONMissing partner item details!

Get the booking status for multiple items

The /booking/status service retrieves the booking status for multiple items based on different criteria.

This service can only be polled every 30 minutes. This would ideally be used in software for bulk updates of pending itineraries.

The maximum number of results returned is 1,000 itineraries. Narrow your search if you expect results greater than this.

NOTE: This will return both live and test bookings.

Example request body

{
  "bookingDateFrom": "2013-03-22",
  "bookingDateTo": "2013-03-25",
  "itineraryIds": null,
  "itemIds": null,
  "distributorRefs": ["Ref20132603_1","Ref20132603_5"],
  "distributorItemRefs": null,
  "leadFirstName": null,
  "leadSurname": null,
  "test": true
}

All fields are optional and can be omitted, however at least one needs to be provided.

FieldMeaning
bookingDateFromThe booking date is greater than or equal this date
bookingDateToThe booking date is less than or equal this date
itemIdsArray of item ids (AKA Viator Item Reference) to check for; e.g., [1234657,2345267,3245154]
distributorRefsArray of partner-defined distributor references; e.g., ["ref1","ref2","ref3"]
distributorItemRefsArray of partner-defined distributor item references; e.g., ["refItem1","refItem2","refItem3"]
leadFirstNameThe lead traveller’s first name
leadSurnameThe lead traveller’s surname
testSetting test to true will bypass the poll limit on the sandbox environment only. The default value for test is false.

Example response object (/booking/status)

{
  "data": [
  {
    "itineraryId": 3332064,
    "bookingStatus": {
      "type": "CONFIRMED",
      "level": "ITINERARY",
      "failed": false,
      "text": "Confirmed",
      "cancelled": false,
      "status": 3,
      "confirmed": true,
      "amended": false,
      "pending": false
    },
    "bookingDate": "2013-03-25",
    "distributorRef": "Ref20132603_1",
    "itemSummaries": [{
      "itineraryId": 3332064,
      "itemId": 600088886,
      "bookingStatus": {
        "type": "CONFIRMED",
        "level": "ITEM",
        "failed": false,
        "text": "Paid &amp;amp; Confirmed",
        "cancelled": false,
        "status": 1,
        "confirmed": true,
        "amended": false,
        "pending": false
      },
      "travelDate": "2013-12-03",
      "distributorItemRef": "ItemRefA",
      "sortOrder": 0
    }],
    "sortOrder": 1
  },
  {
    "itineraryId": 3332076,
    "bookingStatus": {
      "type": "CONFIRMED",
      "level": "ITINERARY",
      "failed": false,
      "text": "Confirmed",
      "cancelled": false,
      "status": 3,
      "confirmed": true,
      "amended": false,
      "pending": false
    },
    "bookingDate": "2013-03-26",
    "distributorRef": "Ref20132603_5",
    "itemSummaries": [{
      "itineraryId": 3332076,
      "itemId": 600088907,
      "bookingStatus": {
        "type": "CONFIRMED",
        "level": "ITEM",
        "failed": false,
        "text": "Paid &amp;amp; Confirmed",
        "cancelled": false,
        "status": 1,
        "confirmed": true,
        "amended": false,
        "pending": false
      },
      "travelDate": "2013-12-03",
      "distributorItemRef": "ItemRefA",
      "sortOrder": 0
    }],
    "sortOrder": 2
  }],
  "vmid": "221002",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-03-26T10:25:57+0000",
  "errorReference": null,
  "errorMessageText": null,
  "success": true,
  "totalCount": 2,
  "errorName": null
}

Exceeding the poll limit

You will receive the following error if you exceed the number of calls allowed to the service within the timeframe:

{
  "data": null,
  "vmid": "221002",
  "errorMessage": [
    "Access allowed every 30 minutes"
  ],
  "errorType": "EXCEPTION",
  "dateStamp": "2013-03-26T10:28:51+0000",
  "errorReference": "~55315512721712161381352771",
  "errorMessageText": [
    "Access allowed every 30 minutes"
  ],
  "success": false,
  "totalCount": 1,
  "errorName": "PollingDeniedException"
}

Get the tour grade pricing matrix

The /booking/pricingmatrix service retrieves the pricing matrix for tour grades, product age bands and pax (passenger) mixes.

Example request object (/booking/pricingmatrix)

  "productCode": "5261HTLAP",
  "tourGradeCode": "Zone 1",
  "bookingDate": "2013-12-01",
  "currencyCode": "USD",
  "specialReservation": false

bookingDate: The date to check for pricing data. This is an optional parameter for a normal product.

If the date is not provided then the nearest available date is determined (i.e. not blocked out or unavailable for any reason)

Example response object (/booking/pricingmatrix)

{
  "data": [{
    "pricingUnit": "per person",
    "bookingDate": "2013-12-01",
    "sortOrder": 1,
    "ageBandPrices": [{
      "bandId": 1,
      "prices": [{
        "sortOrder": 1,
        "currencyCode": "USD",
        "price": 81.94,
        "priceFormatted": "$81.94",
        "merchantNetPrice": 65.44,
        "merchantNetPriceFormatted": "$65.44",
        "minNoOfTravellersRequiredForPrice": 1
      }],
      "sortOrder": 1,
      "minimumCountRequired": 1,
      "maximumCountRequired": 1
    }]
  },
  {
    "pricingUnit": "per person",
    "bookingDate": "2013-12-01",
    "sortOrder": 2,
    "ageBandPrices": [{
      "bandId": 1,
      "prices": [{
        "sortOrder": 1,
        "currencyCode": "USD",
        "price": 40.97,
        "priceFormatted": "$40.97",
        "merchantNetPrice": 32.73,
        "merchantNetPriceFormatted": "$32.73",
        "minNoOfTravellersRequiredForPrice": 1
      }],
      "sortOrder": 1,
      "minimumCountRequired": 2,
      "maximumCountRequired": 2
    }]
  },
  {
    "pricingUnit": "per person",
    "bookingDate": "2013-12-01",
    "sortOrder": 3,
    "ageBandPrices": [{
      "bandId": 1,
      "prices": [{
        "sortOrder": 1,
        "currencyCode": "USD",
        "price": 27.32,
        "priceFormatted": "$27.32",
        "merchantNetPrice": 21.81,
        "merchantNetPriceFormatted": "$65.44",
        "minNoOfTravellersRequiredForPrice": 1
      }],
      "sortOrder": 1,
      "minimumCountRequired": 3,
      "maximumCountRequired": 3
    }]
  }],
  "errorReference": null,
  "dateStamp": "2017-11-24T21:30:47+0000",
  "errorType": null,
  "errorCodes": null,
  "errorMessage": null,
  "errorName": null,
  "success": true,
  "totalCount": 3,
  "errorMessageText": null,
  "vmid": "321050"
}

Description of elements in JSON response object

ObjectElementTypeCommentsTo be viewed by customerRequired field
dataobjectmain response object
sortOrderintegerorder in which to show the pricing
bookingDatedatebooking date criteria
pricingUnitstringunit for pricing: currently, only “per person” is supported
ageBandPricesobjectavailable age bands and their pricing
sortOrderintegersort order for age band display
bandIdintegerNote: the numeric bandId is associated with an age band description (e.g., "Adult", "Infant" etc.) and a corresponding age range (e.g., from 12 to 99) - these details are available from the /product service. See Working with age bands
minimumCountRequiredintegerminimum number of pricing units that apply to these prices
maximumCountRequiredintegermaximum number of pricing units that apply to these prices
pricesobjectpricing available for the age band (based on the min and max count requirements)
currencyCodestringcurrency of the pricing
sortOrderintegerorder the pricing is to be shown within the bandId
pricenumberprice in decimal format (for merchant API partners, this is the ‘suggested sell price’)
priceFormattedstringsuggested sell price formatted according to the currency selected (with two decimal places where applicable)
merchantNetPricenumbermerchant net price in decimal format
merchantNetPriceFormattedstringmerchant net price formatted according to the selected currency
minNoOfTravellersRequiredForPriceintegernumber of units that the pricing applies to (e.g., a minNoOfTravellersRequiredForPrice of 3 means that the price is for three people)

Dealing with vouchers

The /booking/voucher service retrieves details for a complete itinerary or a single itinerary item. The data is returned as HTML that can be wrapped in a header/footer.

Sample URL parameters

leadLastName=DP&amp;itemId=600033670

or

voucherKey=3299307:93c7f36a56b18ba1068787ba7fb7988da5c8ad08db77604110141ff21498603e:600033670

Key concepts

voucherKey

  • Use either the voucherKey or the three separate parameters.
  • If voucherKey is provided as well as other parameters, then the voucherKey overrides the other parameters.
  • The voucherKey is obtained from /booking/mybookings or in the /booking/book response object when a booking is made.

fullHTML

This is an optional parameter:

  • If true, the full HTML (including &lt;!DOCTYPE&gt;, &lt;html&gt; and &lt;head&gt; tags) will be returned.
  • If false, an HTML &lt;div&gt; element will be returned.
  • The default for this parameter is false

mobileVoucher

  • Optional parameter. Defaults to true. If true, the mobile (cut down) voucher HTML is returned; otherwise, the full voucher HTML is returned and fullHTML is ignored
  • This field should only be enabled for products that have a voucherOption of "VOUCHER_E" (electronic voucher). Do not enable mobileVouchers for paper vouchers (voucherOption of "VOUCHER_PAPER_ONLY") as no barcode is returned.
  • The voucher information is available in the responses for:
  • Voucher information is also displayed under the Redemption Info heading in the response from this service.

Example response object (/booking/voucher)

{
  "data": "&lt;div style=\'line-height: 1.5;font-family:\'Arial\',\'Helvetica\',\'Verdana\',sans-serif; font-size: 12px; padding: 0 10px; border-bottom: 1pxsolid #CAE2EA;\'&gt;&lt;h2 style=\'font-size:16px;font-weight:bold;margin:0.5em 0;padding:0;\'&gt;San FranciscoBay Sunset Catamaran Cruise &amp;reg;&lt;/h2&gt;&lt;h2 style=\'font-size:16px;font-weight:bold;margin:0.5em0;padding:0;\'&gt;SAMPLE ONLY&lt;/h2&gt;&lt;ul style=\'margin:0 0 1em 1em; padding:0;\'&gt; &lt;li&gt;&lt;strong&gt;Date:&lt;/strong&gt;Friday April 13, 2012 &lt;/li&gt;&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt;&lt;strong&gt;2011:&lt;/strong&gt;&lt;br&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Nov. 6 to Nov. 27&lt;/strong&gt;: 4:00pm (Fri., Sat. &amp;amp; Sun)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;2012:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;March 2 to March 10:&lt;/strong&gt;&amp;nbsp; 5:00 pm (Fri., Sat. &amp;amp; Sun)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;March 11 to April 15:&lt;/strong&gt; 6:00pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;April 16 to May 20:&lt;/strong&gt; 6:30 pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;May 21 to July 22:&lt;/strong&gt; 7:00 pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;July 23 to Aug 26: &lt;/strong&gt;6:30 pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Aug 27 to Sept 23:&lt;/strong&gt;6:00 pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Sept. 24 to Nov. 3:&lt;/strong&gt; 5:30 pm Daily&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Nov 4 to Dec 2:&lt;/strong&gt; 4:00pm (Friday, Sat., &amp;amp; Sun.)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Please arrive 30 minutes prior to cruise departure.&lt;/li&gt;&lt;/ul&gt; &lt;ul style=\'margin:0 0 1em 1em; padding:0;\'&gt; &lt;li&gt;&lt;strong&gt;Lead Traveler: &lt;/strong&gt; jos dp&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Number of Travelers: &lt;/strong&gt; 1 Adult&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Booking Reference: &lt;/strong&gt;VIATOR600033672&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Product Code: &lt;/strong&gt;2316SUN&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Confirmation Details:&lt;/strong&gt;SUN &lt;/li&gt; &lt;li&gt;&lt;strong&gt;Location &lt;/strong&gt;&lt;div&gt;&lt;p&gt;Pier 39&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;When you get to Pier 39, stand on the sidewalk &amp;amp; look towards the water, do NOT go down the center wherethe shops are, but take the left OUTSIDE walkway. Go towards the sea lions &amp;amp; look for a gate with the letter J on it&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=\'font-size:14px;font-weight:bold;margin:0.5em 0;padding:0;\'&gt; Redemption Info&lt;/h3&gt;&lt;ul style=\'margin:0 0 1em 1em; padding:0;\'&gt; &lt;li&gt;You can present either a paper or an electronic voucherfor this activity. &lt;/li&gt; &lt;/ul&gt; &lt;h3 style=\'font-size:14px;font-weight:bold;margin:0.5em 0;padding:0;\'&gt;Important&lt;/h3&gt; &lt;ul&gt;&lt;li&gt;Your local contact is Adventure Cat Sailing Charters on +1 800 498 4228.&lt;/li&gt;&lt;li&gt;Please note: You mustreconfirm directly with Adventure Cat Sailing Charters at &lt;ul&gt; &lt;li&gt;Locally on 415 777 1630&lt;/li&gt;&lt;/ul&gt; at least 24 Hour(s)prior to your tour/activity date. If you are not arriving within the specified timeframe, please contact Adventure CatSailing Charters prior to your travels, or immediately upon arrival at your destination.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Duringthe months of March, April and November, the weather in San Francisco can be unpredictable and sailings are subject tocancellation or rescheduling. Please ensure that you call the operator 1 day prior to sailing to confirm your tour&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=\'font-size:14px;font-weight:bold;margin:0.5em 0;padding:0;\'&gt;Inclusions&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;1.5-hour Sunset Cruise&lt;/li&gt;&lt;li&gt;Light hors d\'oeuvres&lt;/li&gt;&lt;li&gt;Two complimentary drinks&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=\'font-size:14px;font-weight:bold;margin:0.5em 0;padding:0;\'&gt;Terms and Conditions &lt;/h3&gt; Read our completeTerms &amp; Conditions for information on cancellations, date changes and other modifications to this confirmed reservation. &lt;/div&gt;&lt;!-- end of voucher_item --&gt;&lt;/div&gt;",
  "vmid": "221001",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2012-04-13T10:40:47+0000",
  "success": true,
  "errorReference": null,
  "errorMessageText": null,
  "totalCount": 1,
  "errorName": null
}

Reviewing bookings

The /booking/pastbooking service gets the details of a single specific past booking based on the voucherKey or itemId passed into it.

Sample query Parameters

"email=john.doe@viator.com&amp;itemId=600033670"

or

"voucherKey=3299307:93c7f36a56b18ba1068787ba7fb7988da5c8ad08db77604110141ff21498603e:600033670"

Key concepts

Email

The email address passed must match the email address associated to the itinerary

Departure Details

Departure details, such as the departurePoint, departurePointAddress and departurePointDirections, will be included in the response. These fields may contain HTML escape characters, such as &amp;amp; and special characters that are escaped by a backslash. Ensure that these fields are parsed after receiving the response, or it may cause your JSON to be invalid.

Example response object (/booking/pastbooking):

{
  "errorReference": null,
  "data": {
    "sortOrder": 0,
    "rulesApplied": null,
    "bookingStatus": {
      "status": 3,
      "text": "Confirmed",
      "type": "CONFIRMED",
      "level": "ITINERARY",
      "confirmed": true,
      "pending": false,
      "amended": false,
      "cancelled": false,
      "failed": false
    },
    "itemSummaries": [{
      "sortOrder": 0,
      "rulesApplied": null,
      "bookingStatus": {
        "status": 1,
        "text": "Paid &amp;amp; Confirmed", "type": "CONFIRMED",
        "level": "ITEM",
        "failed": false,
        "confirmed": true,
        "amended": false,
        "pending": false,
        "cancelled": false
      },
      "travellerAgeBands": [{
        "sortOrder": 0,
        "count": 2,
        "pluralDescription": "Adults",
        "description": "Adult",
        "ageBandId": 1
      }],
      "voucherKey": "1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69:700179574",
      "voucherURL": "https://viatorapi.sandbox.viator.com/service/merchant/voucher.jspa?code=1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69:700179574&amp;embedResources=false",
      "voucherRequirements": "You must present a paper voucher for this tour. We will email a link to access and print your voucher at the Lead Travelers email address.",
      "productPulledDown": false,
      "merchantCancellable": true,
      "productWidgetList": null,
      "savingAmount": 0,
      "vouchers": null,
      "passbooks": null,
      "termsAndConditions": null,
      "itineraryId": 1000308214,
      "productCode": "2065CPT",
      "tourGradeCode": "1DAY",
      "distributorItemRef": "distroItemRefJDP1006151732",
      "languageServicesLanguageCode": "en",
      "travelDate": "2015-09-03",
      "price": 26.28,
      "leadTravellerSurname": "Test",
      "barcodeOption": "tour",
      "barcodeType": "code128",
      "destId": 318,
      "voucherOption": "VOUCHER_PAPER_ONLY",
      "productTitle": "City Sightseeing Cape Town Hop-On Hop-Off Tour",
      "itemId": 700179574,
      "obfsId": 27643,
      "departurePoint": "Tour starts at V&amp;amp;A Waterfront, outside the Two Oceans Aquarium, however you may board the bus at any one of the stops throughout the city (see the Itinerary section below for a list of stops)",
      "departurePointAddress": "",
      "departurePointDirections": "",
      "leadTravellerTitle": "Mr",
      "leadTravellerFirstname": "Homer",
      "lastRetailPrice": 26.28,
      "bookingEngineId": "UF",
      "priceFormatted": "$26.28",
      "savingAmountFormated": "",
      "merchantNetPrice": 26.28,
      "merchantNetPriceFormatted": "$26.28",
      "currencyCode": "USD",
      "lastRetailPriceFormatted": "$26.28",
      "departsFrom": "Cape Town, South Africa",
      "tourGradeDescription": "1-Day Bus Tour (1DAY)",
      "hoursConfirmed": 0,
      "priceUSD": 26.28
    }],
    "voucherURL": "https://viatorapi.sandbox.viator.com/service/merchant/voucher.jspa?code=1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69&amp;embedResources=false",
    "voucherKey": "1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69",
    "bookerEmail": "jocelyn@viator.com",
    "itineraryId": 1000308214,
    "exchangeRate": 1,
    "distributorRef": "distroRefJDP1006151732",
    "totalPrice": 26.28,
    "bookingDate": "2015-06-10",
    "totalPriceFormatted": "$26.28",
    "totalPriceUSD": 26.28,
    "hasVoucher": true,
    "userId": null,
    "currencyCode": "USD"
  }
}

Checking bookings

The /booking/mybookings service gets a user’s future bookings; i.e., those with travel dates in the future. This service can also be used to check the status of a booking.

Key concepts

Sample URL parameters

  • "sessionId=xxx", or
  • "voucherKey=xxx", or
  • "email=terry.smith@viator.com&amp;lastCCFourDigits=4242", or
  • "email=terry.smith@viator.com&amp;itineraryOrItemId=3299307"

Provide one of:

  • a sessionId for all bookings related to a user account, or
  • a voucherKey, or
  • an email address (email) and the last four digits of the credit card number (lastCCFourDigits) used to make the booking to get all associated bookings, or
  • an email address (email) and itemId

…in that order

For "Failed" items, display a message that communicates the following information to your customers:

<pre>“The booking has failed either because this tour or activity was not available or there was a technical issue. Please contact Customer Service if you need more information."</pre>

See also: Booking and item status list

Departure details

Departure details, such as the departurePoint, departurePointAddress and departurePointDirections will be included in the response. These fields may contain HTML escape characters, such as &amp;amp; and special characters that are escaped using a backslash. Ensure that these fields are parsed after receiving the response or it may cause your JSON to be invalid.

Example response object (/booking/mybookings):

{
  "errorReference": null,
  "data": {
    "sortOrder": 0,
    "rulesApplied": null,
    "bookingStatus": {
      "status": 3,
      "text": "Confirmed",
      "type": "CONFIRMED",
      "level": "ITINERARY",
      "confirmed": true,
      "pending": false,
      "amended": false,
      "cancelled": false,
      "failed": false
    },
    "itemSummaries": [{
      "sortOrder": 0,
      "rulesApplied": null,
      "bookingStatus": {
        "status": 1,
        "text": "Paid &amp;amp; Confirmed",
        "type": "CONFIRMED",
        "level": "ITEM",
        "failed": false,
        "confirmed": true,
        "amended": false,
        "pending": false,
        "cancelled": false
      },
      "travellerAgeBands": [{
        "sortOrder": 0,
        "count": 2,
        "pluralDescription": "Adults",
        "description": "Adult",
        "ageBandId": 1
      }],
      "voucherKey": "1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69:700179574",
      "voucherURL": "https://viatorapi.sandbox.viator.com/service/merchant/voucher.jspa?code=1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69:700179574&amp;embedResources=false",
      "voucherRequirements": "You must present a paper voucher for this tour. We will email a link to access and print your voucher at the Lead Travelers email address.",
      "productPulledDown": false,
      "merchantCancellable": true,
      "productWidgetList": null,
      "savingAmount": 0,
      "vouchers": null,
      "passbooks": null,
      "termsAndConditions": null,
      "itineraryId": 1000308214,
      "productCode": "2065CPT",
      "tourGradeCode": "1DAY",
      "distributorItemRef": "distroItemRefJDP1006151732",
      "languageServicesLanguageCode": "en",
      "travelDate": "2015-09-03",
      "price": 26.28,
      "leadTravellerSurname": "Test",
      "barcodeOption": "tour",
      "barcodeType": "code128",
      "destId": 318,
      "voucherOption": "VOUCHER_PAPER_ONLY",
      "productTitle": "City Sightseeing Cape Town Hop-On Hop-Off Tour",
      "itemId": 700179574,
      "obfsId": 27643,
      "departurePoint": "Tour starts at V&amp;amp;A Waterfront, outside the Two Oceans Aquarium, however you may board the bus at any one of the stops throughout the city (see the Itinerary section below for a list of stops)",
      "departurePointAddress": "",
      "departurePointDirections": "",
      "leadTravellerTitle": "Mr",
      "leadTravellerFirstname": "Homer",
      "lastRetailPrice": 26.28,
      "bookingEngineId": "UF",
      "priceFormatted": "$26.28",
      "savingAmountFormatted": "",
      "merchantNetPrice": 26.28,
      "merchantNetPriceFormatted": "$26.28",
      "currencyCode": "USD",
      "lastRetailPriceFormatted": "$26.28",
      "departsFrom": "Cape Town, South Africa",
      "tourGradeDescription": "1-Day Bus Tour (1DAY)",
      "hoursConfirmed": 0,
      "priceUSD": 26.28
    }],
    "voucherURL": "https://viatorapi.sandbox.viator.com/service/merchant/voucher.jspa?code=1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69&amp;embedResources=false",
    "voucherKey": "1000308214:899757cf8b419ed11f39045636b0b30af986d19126d04547097f4b9c05fb4b69",
    "bookerEmail": "jocelyn@viator.com",
    "itineraryId": 1000308214,
    "exchangeRate": 1,
    "distributorRef": "distroRefJDP1006151732",
    "totalPrice": 26.28,
    "bookingDate": "2015-06-10",
    "totalPriceFormatted": "$26.28",
    "totalPriceUSD": 26.28,
    "hasVoucher": true,
    "userId": null,
    "currencyCode": "USD"
  },
  "dateStamp": "2015-06-10T00:33:24+0000", "errorType": null,
  "errorMessage": null,
  "errorName": null,
  "success": true,
  "totalCount": 1,
  "vmid": "321004",
  "errorMessageText": null
}

Testing

Postman collection for testing

To facilitate your testing of the APIs functionality in the sandbox environment, please use the following file, which can be loaded into the Postman API development environment via its import function:

Setting up API-key authentication in Postman

Before you start using the linked Postman collection for testing, you will need to set up the authorization method you wish to use. This can be either the new method (the exp-api-key <u>header</u> parameter) or, the legacy method (the apiKey <u>query</u> parameter).

While both methods remain available, we strongly recommend that you use the new method, as it:

  1. Provides access to all languages available for your organization with a single API-key as opposed to one API-key per language
  2. Allows access to the new booking cancellation endpoints, as well as all newly-created endpoints in future

Please speak to your account manager if you are still using the legacy apiKey and would like to switch to our new authentication mechanism.

How to set up the new exp-api-key header parameter

  1. Select Edit from the collection menu:

postman-testing-1

  1. Set the following values:
  • Key: exp-api-key
  • Value: Your organization’s single exp-api-key, which will have an identical format to that shown in the image below
  • Add to: Header

postman-testing-2

  1. Click Update

How to set up the legacy apiKey query parameter

  1. Select Edit from the collection menu:

postman-testing-1

  1. Set the following values:
  • Key: apiKey
  • Value: One of your organization’s legacy apiKeys, which will have an identical format to that shown in the image below
  • Add to: Query Params

postman-testing-3

  1. Click Update

FAQs

Is a confirmation email sent to the customer or supplier when a booking is made in the sandbox environment?

  • No.

How do I make a demo booking?

  • To make a demo booking, make sure you set demo to true in your request to the /booking/book service.

What should I do if I successfully create a test booking in the Live environment?

  • Firstly, please don’t make test bookings in the Live environment, as doing so may cause a confirmation email to be sent to the product supplier. Nonetheless, if you have made a test booking, cancel it using the /bookings/{id}/cancel service; or, send an email to dpsupport@viator.com and include both “CANCEL” and the booking reference number in the subject line.

Which currencies can I use when making a booking?

  • You can make a booking using the /booking/book endpoint using any of the supported currencies.
  • If you attempt to use a non-supported currency, you will receive an error message similar to the following:
{
  "errorReference": "3D45567E:2D4A_0A5D033A:01BB_5F616D10_1FBBC9:7035",
  "data": null,
  "dateStamp": "2020-09-15T18:41:00+0000",
  "errorType": "EXCEPTION",
  "errorCodes": [
    "UNKNOWN_ERROR"
  ],
  "errorMessage": [
    "Merchant API does not allow the specified currency"
  ],
  "errorName": "RuntimeException",
  "extraInfo": {},
  "extraObject": null,
  "success": false,
  "totalCount": 1,
  "errorMessageText": [
    "Merchant API does not allow the specified currency"
  ],
  "vmid": "331001"
}

Why am I having an SSL handshake issue?

What is the difference between merchantNetPrice and price in the response from the /search/products service?

  • merchantNetPrice is the amount you, as the merchant partner, will be invoiced for, excluding any fees.
  • price is the price at which Viator sells the product

Why is a different price displayed in /booking/availability/tourgrades and /product

A destination is missing its latitude, longitude or time zone

  • Some destinations in the sandbox environment may be missing geolocation or time zone data. However, if you encounter a destination in the Live environment with missing information, this can be regarded as an unintended omission – please contact us so that we can update our destination information.

How do I make a test booking?

To make a test booking, make sure you:

  • set firstname and/or surname in the booker object to 'test'.
  • set demo to true

Example:

{
  "demo": true,
  "currencyCode": "USD",
  "partnerDetail": {
    "distributorRef": "distroRef0412141435"
  },
  "booker": {
    "email": "apitest@viator.com",
    "firstname": "Test",
    "surname": "Test",
    "title": "Mr"
  },
  "items": [{
    "partnerItemDetail": {
      "distributorItemRef": "distroItemRef0412141435_1"
    },
    "hotelId": null,
    "pickupPoint": null,
    "travelDate": "2015-03-31",
    "productCode": "2916ROME",
    "tourGradeCode": "24HR",
    "languageOptionCode": "en/SERVICE_GUIDE",
    "bookingQuestionAnswers": [{
      "questionId": 100,
      "answer": "120 kgs"
    }],
    "specialRequirements": "",
    "travellers": [{
      "bandId": 1,
      "firstname": "Homer",
      "surname": "Simpson Test",
      "title": "Mr",
      "leadTraveller": true
    }]
  }]
}

Is it possible to use a custom value for distributorRef and distributorItemRef

  • Yes! In fact, this is what you’re supposed to do. You can pass anything you like in these fields; however, if you use a distributorRef that has already been used, the API will return the previous booking made with that distributorRef rather than creating a new booking.
  • Note: distributorRef must be fewer than 40 characters

What are some common reasons for bookings to fail in the Viator API?

  • homePhone or any phone field in the booking request contains spaces. The only acceptable non-numeric characters are: “-“, “+” , “(“, and “)”

  • distributorRef has been re-used. When making a booking request, a distributorRef and distributorItemRef must be provided. This is the partner’s ID for the booking, and it must be unique. If a distributorRef has been re-used, a booking will not be made and instead, the existing booking will be returned in the response.

  • distributorRef exceeds 40 characters

  • No traveller or an incorrect traveller has been set as the lead traveller in the booking request;

    • leadTraveller:true must be set for one traveller
    • the leadTraveller must be from an ageBand that has treatAsAdult set to true. The data is available in the ageBands object in the product details service.
  • languageOptionCode is invalid

    • To find the valid language option codes for a particular product, have a look at the langServices object in the response from the /product service; e.g.,
"langServices": {
  "en/SERVICE_AUDIO": "English - Audio"
}
  • You must then ensure that the languageOptionCode in the request to the /booking/book service is populated in the same way; i.e.,
"languageOptionCode": "en/SERVICE_AUDIO"

What does it mean if I receive a “Section level access denied” error message?

  • This means that your API-key does not have the correct permissions to access the particular service you were attempting to access when you received this error message. If you feel you would like to use this service nonetheless in your implementation, please contact your account manager to discuss having access granted.

What does it mean if I receive a “503 Service Unavailable” response?

  • This means that there was a temporary service outage on our end at that time. We recommend that you re-try the operation until you no longer receive this error.

Does API rate limiting apply to all services?

  • Yes, it does. Regardless of the service you are making requests to, the fundamental rate limits apply equally.

Can I cancel multiple bookings or items at the same time using the Viator API?

  • No, you may only cancel one booking at a time.

How many concurrent requests can be made of the API from the same IP address?

  • Three.

Will my API-key expire?

  • If any API-key is not used for a period of six months, that key is automatically deactivated as a security measure. If this has happened to you, contact your account manager to have the key reactivated or a new key issued to you.

Why am I getting an empty response when checking booking details?

  • If you are attempting to check a booking using the /booking/status or /booking/status/items endpoints and receive an empty response, it may be that the booking was made with the demo parameter set to true, as the booking status endpoints will ignore demo bookings. Please try making the booking again, ensuring the demo parameter is set to false. If this also fails, please email dpsupport@viator.com and include a copy of the request and response JSON objects.

Must I always provide details for all travelers when booking a product where allTravellerNamesRequired=true?

  • Approximately 45% of the products in our catalog require all traveller details to be supplied at the time of booking, and this requirement is enforced by the API. While it is technically possible to bypass this requirement – for example, by setting the lead traveler’s name, but using dummy values for the the remaining travelers’ details (’traveler 2’, etc.) – we strongly advise against this, as it can cause problems for suppliers for whom this is a strict requirement. Examples include: Alcatraz tickets, theme park tickets that require a QR code, bookings for flights needing to meet TSA requirements; or, vehicle, Segway or jet-ski rentals. If you are unable to implement the collection of all traveler details on your site, we recommend filtering-out products where this is a strict requirement. You may also request that we filter-out these products for you so that they do not appear in product search results.

Must I always provide answers to the required booking questions when making a booking?

  • Yes. You must provide answers to all necessary booking questions when making a booking. Approximately 40% of the products in our catalog have booking questions, some of which may be necessary to fulfil the suplier’s legal requirements. In the case that the customer cannot provide specific details at the time of booking – e.g., a departure flight number – they may enter ‘unknown’ and the supplier will manually send a follow-up message to ask for this information.

Why is there such a big difference in price between that given in the product endpoints and the actual price at the time of booking?

  • The price returned in the product endpoints is the ‘From Price’, which is the <u>lowest possible price</u> for an adult passenger when taking into account all available tour grades, group bookings and so forth. The exact price can only be determined when you check the availability for a specific date and passenger/traveler mix. We recommend using the /booking/availability/tourgrades endpoint for this purpose.

Why doesn’t the /taxonomy/destinations endpoint return continent-level information?

  • Products are categorized according to their ‘destination’, which includes cities, regions and countries. The next logical grouping would be ‘by continent’; however, this would be too broad a grouping, resulting in too many search results and lengthy response times if the product catalogue were to be searched by continent. For more information, see: Categorization of content

Will there ever be a discrepancy between the amount charged for a tour and the amount refunded due to currency exchange-rate fluctuations?

  • In short: no. Firstly, the cost of the booking and the refund amount are always calculated in the product supplier’s native currency – no exchange rate calculations are applied. I.e., if the cost of the booking was USD 100 and the refund percentage is 100% (full refund, as per the response from /bookings/{booking-reference}/cancel-quote), Viator will simply not invoice you for that USD 100 that we would have if the booking was not canceled. Furthermore, we do not invoice you for the cost of a booking prior to its departure date.

Appendices

Update log

DateDescription
20 July 2020Added Booking references section
14 July 2020Updated Calculating prices section
2 June 2020Updated Postman collections and Testing section
18 May 2020Added note regarding cancel codes to Legacy merchant cancellation section
7 May 2020Upgraded search feature; enabled ‘Try it Out’ console
10 Mar 2020Created new Overview section; removed ‘Availability services’ section, moving section contents into Key Concepts section

Accept-Language header

The Accept-Language header parameter controls which language the natural language fields in the response from each endpoint will be translated into.

Note that you can only specify languages that have been configured for your API-key. Therefore, if you wish to access additional languages, you will need to contact your business development account manager.

LanguageAccept-Language parameter value
Englishen, en-US
Danishda, da-DK
Dutchnl, nl-NL
Norwegianno, no-NO
Spanishes, es-ES
Swedishsv, sv-SE
Frenchfr, fr-FR
Italianit, it-IT
Germande, de-DE
Portuguesept, pt-PT
Japaneseja, ja-JP
Chinese (simplified)zh-CN
Chinese (traditional)zh-TW
Koreanko, ko-KR

Standard JSON fields

Every service returns a standard set of JSON fields at the end of the JSON response, which indicates if it was processed successfully by the API.

In addition to the success flag, you will also need to check the errorMessage values for the status of the response.

An error-free response will have:

  • "success":true
  • "errorType":null
  • "errorMessage":null

Example JSON - successful:

{
  "data": [],
  "vmid": "321001",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-03-06T19:45:10+0000",
  "errorReference": null,
  "errorMessageText": null,
  "success": true,
  "totalCount": 114,
  "errorName": null
}

Example JSON - unsuccessful:

{
  "errorReference": "~5793740141815885188840666",
  "data": null,
  "dateStamp": "2013-09-09T11:29:48+0000",
  "errorType": "EXCEPTION",
  "errorMessage": ["* Additional questions missing\n"],
  "errorName": "ValidationException",
  "success": false,
  "totalCount": 1,
  "vmid": "221001",
  "errorMessageText": ["* Additional questions missing" ]
}
ElementTypeCommentsTo be viewed by customerRequired
vmidstringThe server id that processed the service
errorMessagestringThe error message in HTML
errorTypestringType of error: EXCEPTION
dateStampstringtimestamp of the response
errorReferencestringThe error reference is logged for future reference
errorMessageTextstringThe textual version of the error message✅<br /> (if an error has occurred)
successboolean<ul><li>true if the API request was successful with no errors</li><li>false if an error was encountered</li></ul>
totalCountintegerThe number of results returned (minimum = 1)✅<br /> (if displaying the number of results found in a search etc.)
errorNamestringThe name of the error type

Country codes

Country codeCountry
AFAfghanistan
ALAlbania
DZAlgeria
ASAmerican Samoa
ADAndorra
AOAngola
AIAnguilla
AQAntarctica
AGAntigua and Barbuda
ARArgentina
AMArmenia
AWAruba
AUAustralia
ATAustria
AZAzerbaijan
BSBahamas
BHBahrain
BDBangladesh
BBBarbados
BYBelarus
BEBelgium
BZBelize
BJBenin
BMBermuda
BTBhutan
BOBolivia
BABosnia Herzegovina
BWBotswana
BRBrazil
BNBrunei
BGBulgaria
BFBurkina Faso
BIBurundi
KHCambodia
CMCameroon
CACanada
CVCape Verde
KYCayman Islands
CFCentral Africa
TDChad
CLChile
CNChina
CXChristmas Island
CCCocos (Keeling) Islands
COColombia
KMComoros
CKCook Islands
CRCosta Rica
CICote D’Ivoire
HRCroatia
CYCyprus
CZCzech Republic
DKDenmark
DJDjibouti
DMDominica
DODominican Republic
ECEcuador
EGEgypt
SVEl Salvador
GQEquatorial Guinea
EREritrea
EEEstonia
ETEthiopia
FKFalkland Island
FOFaroe Islands
FJFiji
FIFinland
FRFrance
GFFrench Guiana
PFFrench Polynesia
GAGabon
GMGambia
GEGeorgia
DEGermany
GHGhana
GIGibraltar
GRGreece
GLGreenland
GDGrenada
GPGuadeloupe
GUGuam
GTGuatemala
GNGuinea
GWGuinea Bissau
GYGuyana
HTHaiti
HNHonduras
HKHong Kong
HUHungary
ISIceland
INIndia
IDIndonesia
IQIraq
IEIreland
ILIsrael
ITItaly
JMJamaica
JPJapan
JOJordan
KZKazakhstan
KEKenya
KIKiribati
KWKuwait
KGKyrgyzstan
LALao People’s Democratic Republic
LVLatvia
LBLebanon
LSLesotho
LRLiberia
LYLibyan Arab Jamahiriya
LILiechtenstein
LTLithuania
LULuxembourg
MOMacau
MKMacedonia
MGMadagascar
MWMalawi
MYMalaysia
MVMaldives
MLMali
MTMalta
MQMartinique
MRMauritania
MUMauritius
YTMayotte
MXMexico
FMMicronesia
MDMoldova
MCMonaco
MNMongolia
MSMonserrat
MAMorocco
MZMozambique
NANamibia
NRNauru
NPNepal
NLNetherlands
ANNetherlands Antilles
KNNevis- St Kitts
NCNew Caledonia
NZNew Zealand
NINicaragua
NENiger
NGNigeria
NUNiue
NFNorfolk Island
KPNorth Korea
MPNorthern Mariana Islands
NONorway
OMOman
PKPakistan
PWPalau
PSPalestinian Territory, Occupied
PAPanama
PGPapua New Guinea
PYParaguay
PEPeru
PHPhilippines
PNPitcairn
PLPoland
PTPortugal
PRPuerto Rico
QAQatar
REReunion
RORomania
RURussian Federation
RWRwanda
SHSaint Helena
LCSaint Lucia
SMSan Marino
STSao Tome and Principe
SASaudi Arabia
SNSenegal
YUSerbia and Montenegro
SCSeychelles
SLSierra Leone
SGSingapore
SKSlovakia
SISlovenia
SBSolomon Islands
SOSomalia
ZASouth Africa
KRSouth Korea
ESSpain
LKSri Lanka
PMSt Pierre Miquelon
VCSt Vincent and Grenadines
SRSuriname
SZSwaziland
SESweden
CHSwitzerland
SYSyria
TWTaiwan
TJTajikistan
TZTanzania
THThailand
TLTimor-Leste
TGTogo
TKTokelau
TOTonga
TTTrinidad and Tobago
TNTunisia
TRTurkey
TMTurkmenistan
TCTurks and Caicos Islands
TVTuvalu
UGUganda
UAUkraine
AEUnited Arab Emirates
GBUnited Kingdom
UYUruguay
UMUS Minor Outlying Islands
USUnited States of America
UZUzbekistan
VUVanuatu
VEVenezuela
VNVietnam
VGVirgin Islands-British
VIVirgin Islands-US
WFWallis and Futuna Islands
WSWestern Samoa
YEYemen Republic
ZMZambia
ZWZimbabwe

US state codes

State codeState
ALAlabama
AKAlaska
AZArizona
ARArkansas
CACalifornia
COColorado
CTConnecticut
DEDelaware
DCDistrict of Columbia
FLFlorida
GAGeorgia
HIHawaii
IDIdaho
ILIllinois
INIndiana
IAIowa
KSKansas
KYKentucky
LALouisiana
MEMaine
MDMaryland
MAMassachusetts
MIMichigan
MNMinnesota
MSMississippi
MOMissouri
MTMontana
NENebraska
NVNevada
NHNew Hampshire
NJNew Jersey
NMNew Mexico
NYNew York
NCNorth Carolina
NDNorth Dakota
OHOhio
OKOklahoma
OROregon
PAPennsylvania
RIRhode Island
SCSouth Carolina
SDSouth Dakota
TNTennessee
TXTexas
UTUtah
VTVermont
VAVirginia
WAWashington
WVWest Virginia
WIWisconsin
WYWyoming

Canadian provinces

CodeProvince
AlbertaAlberta
British ColumbiaBritish Columbia
ManitobaManitoba
New BrunswickNew Brunswick
Newfoundland and LabradorNewfoundland
Northwest TerritoriesNorthwest Territories
Nova ScotiaNova Scotia
NunavutNunavut
OntarioOntario
Prince Edward IslandPrince Edward Island
QuebecQuebec
SaskatchewanSaskatchewan
YukonYukon Territory

Australian states

CodeState
ACTAustralian Capital Territory
NSWNew South Wales
NTNorthern Territory
QLDQueensland
SASouth Australia
TASTasmania
VICVictoria
WAWestern Australia

bookingStatus field values and meanings

Field: typeField: statusMeaning
"WAITING"0This item has not been booked. Part of an unfinished itinerary.
"CONFIRMED"1This item has been successfully booked
"UNAVAILABLE"2This item has been had an availability check, that came back false.
"PENDING"3This item has begun booking, but has paused in a deferred booking engine
"FAILED"4A merchant partner with a freesale-only API-key has attempted to book an on-request product
"CANCELLED"5This item has successfully been cancelled.
"EXPIRED"6This item is now expired.
"AMENDED"7This item has been amended after booking.
"PENDING_AMEND"8This item has a pending amendment which can be cancelled.
"REJECTED"12Viator only
"ON_HOLD"13Viator only

Supported currency codes

Supported currency codes for merchant partners:

Currency codeCurrency
USDUS dollar
GBPBritish pound
EUREuro
AUDAustralian dollar

Note: Partners will be billed in the currency of the booking.

Viator API error codes

Error codeServicesError messageDescription
ADDRESS_REQUIRED/booking/book“You have not entered an address. Please enter your address information.”ccAddress1 was empty
ADDRESS_SIZE_EXCEEDED/booking/book“Billing address is restricted to 50 characters long.”address field was longer than 51 characters
ATTRIBUTE_NOT_FOUND/product
AGE_BAND_INVALID/booking/booka bandId has been submitted that does not correspond to any bandId available for the tour grade in question
BOOKING_QUESTIONS_MISSING/booking/book“Additional questions missing”one or more required booking questions are missing in the booking request
CARD_EXPIRED/booking/booksubmitted credit card details corresponding to an expired card
CITY_REQUIRED/booking/book“You have not entered a city in the address section. Please enter your city.”address is required in the credit card section
CITY_SIZE_EXCEEDED/booking/book“City is restricted to 40 characters long.”city name submitted was more than 40 characters long
COUNTRY_REQUIRED/booking/book“You have not entered a country. Please enter your country.”no country was submitted in the booking request
CREDIT_CARD_DECLINED/booking/bookcredit card used for booking was declined by the payment processor
CREDIT_CARD_EXPIRY_DATE_INVALID/booking/book“The expiration date for your credit card is not formatted properly. Please verify and re-enter the expiration date.”incorrectly-formatted credit card expiration date was submitted
CREDIT_CARD_HOLDER_NAME_INVALID/booking/bookcredit card holder’s name was invalid, perhaps due to the inclusion of invalid characters
CREDIT_CARD_NUMBER_INVALID/booking/book“Please verify and re-enter the credit card details, or use a different credit card”invalid characters in credit card number
CREDIT_CARD_NUMBER_REQUIRED/booking/book“Credit card number is required”credit card number was omitted
CREDIT_CARD_SECURITY_NUMBER_INVALID/booking/book“The card security number you entered for your credit card is invalid. It must contain 3 digits (or 4 with American Express cards). Please re-enter the card security number.”incorrect CCV code submitted
CREDIT_CARD_SECURITY_NUMBER_REQUIRED/booking/book“Credit card security number is required”CCV was not provided
DEMO_BOOKING_WITH_REAL_CARD/booking/pricingmatrixdemo is true, but credit card details are real
DISTRIBUTOR_REFERENCE_MISMATCH/booking/pastbooking; /booking/mybookings“The distributor reference associated with this itinerary does not match the one provided.”attempt to retrieve a booking with an itineraryId or itemId and distributorRef, but the reference doesn’t match the one saved in the itinerary
EMAIL_ADDRESS_INVALID/booking/book“Your email address format is invalid”email address is formatted incorrectly
EMAIL_REQUIRED/booking/book“Email is required”email address is missing in the booking request
FIRST_NAME_INVALID/booking/book“You have entered a name for the credit-card holder that is not valid. Please verify and re-enter the name of the credit card holder.”first name is formatted incorrectly or contains invalid characters in the booking request - string length must be > 1 and must not contain the following characters: <>%;”(),
FIRST_NAME_REQUIRED/booking/book“First name of credit card details is required”no first name specified
FIRST_NAME_SIZE_EXCEEDED/booking/book“First name of credit card details is restricted to 30 characters long”first name exceeds 30 characters
INTERNAL_ERRORanyanythe API itself has experienced an unexpected error
LAST_NAME_INVALID/booking/book“You have entered a name for the credit-card holder that is not valid. Please verify and re-enter the name of the credit card holder.”last name is formatted incorrectly in the booking request - string length must be > 1 and must not contain the following characters: <>%;”(),
LAST_NAME_REQUIRED/booking/book“Last name of credit card details is required”no last name supplied in the ccname field of the ccPayDetail object
LAST_NAME_SIZE_EXCEEDED/booking/book“Last name of credit card details is restricted to 35 characters long”the surname in the ccname field of the ccPayDetail object must not exceed 35 characters in length
LEAD_TRAVELLER_REQUIRED/booking/book“A traveler needs to be selected as lead traveler.”one traveller object within the travellers array in the booking request needs to have leadTraveller set to true
PAYMENT_AMOUNTS_CHANGED/booking/booke.g. “PAYMENT_AMOUNTS_CHANGED: HKD 2213.20 (was HKD 2210.26)”This error indicates that the exchange rate was updated while the booking was being made. Refresh the product’s pricing information and retry the booking.
PAYMENT_CURRENCY_MISMATCH/booking/book
PAYMENT_ENCRYPTION_ERROR/booking/bookViator-only internal error - retry booking request
PAYMENT_INTERNAL_ERROR/booking/bookViator-only internal error - retry booking request
PAYMENT_LIMIT_REACHED/booking/bookViator-only internal error - retry booking request
PAYMENT_REJECTED/booking/booktriggered when expiry: "01/2018" and card number: "4539791001730106" were submitted
POSTCODE_REQUIRED/booking/book“You have not entered a zip code / post code. Please enter your zip code / post code.”,ccaddressZip was empty
POSTCODE_SIZE_EXCEEDED/booking/book“Zip code / post code is restricted to 10 characters long.”ccaddressZip was more than 10 characters in length
PRICING_DATA_MISSINGViator-only internal error - retry booking request
PRODUCT_TOUR_GRADE_UNKNOWN/booking/pricingmatrixUnknown tour grade: <TOUR_GRADE> for productan invalid tour grade code was submitted
PRODUCT_UNAVAILABLE/booking/bookViator-only internal error - retry booking request
REFUND_REJECTEDViator-only internal error - retry booking request
STATE_REQUIRED/booking/bookccaddressState is required for this billing request
STATE_SIZE_EXCEEDED/booking/bookccaddressState must be fewer than 35 characters long
TOUR_NOT_AVAILABLE/booking/book“We’re sorry, the following tour you are trying to book is sold out and no longer available”the tour is not available on the requested date
TOUR_GONE/product“We’re sorry, we cannot find the tour, activity or attraction you are looking for”no product corresponding to the supplied details was found
TOUR_NOT_AVAILABLE_BETWEEN_DATES
TOUR_NOT_FOUND/product“We’re sorry, we cannot find the tour, activity or attraction you are looking for”no product corresponding to the supplied details was found
TRAVELLER_COUNT_EXCEEDED_MAX_LIMITnumber of travellers in the booking request was greater than the limit for the product being booked
TRAVELLER_FIRST_NAME_INVALID/booking/book“First name of traveler 1 must only contain alphabetical characters”non-alphabetical characters were used in the traveller’s first name
TRAVELLER_FIRST_NAME_REQUIRED/booking/book“First name of traveler 1 is required”firstname in the booker object was omitted
TRAVELLER_LAST_NAME_INVALID/booking/book“Last name of traveler 1 should contain alphabet only”surname in the booker object contained non-alphabetical characters
TRAVELLER_LAST_NAME_REQUIRED/booking/book“Last name of traveler 1 is required”surname in the booker object was omitted
TRAVELLER_MISMATCH/booking/availability/tourgradesthe bandId is not available for the selected tour grade; or, the product does not support the number of travelers requested
UNKNOWN_ERRORanyanythe API reports this error when the exception from the underlying system (e.g. booking server) is not recognized
UNKNOWN_PAYMENT_METHOD
UNSUPPORTED_CARDcctype is not one of "Visa", "Mastercard" or "Amex"

Booking questions

Example product codes were valid at the time of writing. If you find that any of these product codes are invalid or do not include the relevant booking question, please inform us about it via email.

IdstringQuestionIdtitlesubtitlemessageexample product
1dateOfBirth_dobDate of Birth(e.g. 20 October 1970)Enter your date of birth.100009P2
2heights_passengerHeightsPassenger Heights(eg. 5'2, 158cm etc)For safety reasons you must enter the height of all passengers. Please indicate inches or centimetres.100009P1
3passport_expiryPassport Expiry Date(e.g. 15 September 2015. If multiple passengers, separate each entry e.g. 01 July 2012, 31 May 2014)Enter passport expiry date for all passengers100014P10
4passport_nationalityPassport Nationality(e.g. United States of America. If multiple passengers, separate each entry e.g. Australia, China)Enter country of issue of passport for all passengers100014P10
5passport_passportNoPassport Number(e.g. 0123456789. If multiple passengers, separate each entry e.g. 0123456789, 9876543210)Enter passport number for all passengers100014P10
6N/AN/AN/AN/AN/A
7transfer_air_arrival_airlineArrival Airline(e.g. United, British Airways, Qantas, etc)Enter the name of your airline.100006P15
8transfer_air_arrival_flightNoArrival Flight No(e.g. UA 864, BA 923, QA 233, etc)Enter your flight number.100006P15
9transfer_air_departure_airlineDeparture Airline(e.g. United, British Airways, Qantas, etc)Enter the name of your airline.100006P17
10transfer_air_departure_flightNoDeparture Flight No(e.g. UA 864, BA 923, QA 233, etc)Enter your flight number.100006P17
11transfer_arrival_dropOffDrop Off Location(e.g. 1234 Cedar Way, Brooklyn, NY 00123)Enter the address for drop off.100006P15
12transfer_arrival_timeArrival Time(eg. 8pm, 20:30 etc)Enter your arrival time. Please indicate AM/PM or use the 24-hour clock.100006P15
13transfer_departure_dateDeparture date(e.g. 15 September 2015)Enter your departure date.100006P15
14transfer_departure_pickUpPick up Location(e.g. 1234 Cedar Way, Brooklyn, NY 00123)Enter the address for pick up.100006P17
15transfer_departure_timeDeparture Time(eg. 8pm, 20:30 etc)Enter your departure time. Please indicate AM/PM or use the 24-hour clock.100006P17
16transfer_port_arrival_timeDisembarkation Time(eg. 8pm, 20:30 etc)Enter your disembarkation time. Please indicate AM/PM or use the 24-hour clock.100014P14
17transfer_port_cruiseShipCruise Ship(e.g. Brilliance of the Seas, etc)Enter your cruise ship.100014P14
18transfer_port_departure_timeBoarding Time(eg. 8pm, 20:30 etc)Enter your boarding time. Please indicate AM/PM or use the 24-hour clock.100014P4
19transfer_rail_arrival_lineArrival Rail Line(e.g. Amtrak, etc)Enter the name of the rail provider.100006P15
20transfer_rail_arrival_stationArrival Rail Station(e.g. Central Station, etc)Enter name of arrival and/or departure station.100006P15
21transfer_rail_departure_lineDeparture Rail Line(e.g. Amtrak, etc)Enter the name of the rail provider.100014P10
22transfer_rail_departure_stationDeparture Rail Station(e.g. Central Station, etc)Enter name of arrival and/or departure station.100014P10
23weights_passengerWeightsPassenger Weights(e.g. 127 pounds, 145 kilos, etc)For safety reasons you must enter the weight of <b>all</b> passengers. Please indicate pounds or kilos.100111P12

Legacy merchant cancellation

Note: This functionality has been replaced by the cancellationReasons, bookingQuote and cancelBooking endpoints.

Requirements for cancellations

  • To successfully cancel a booking via the /merchant/cancellation service, you must include the itinerary item to cancel (itemId).

  • itineraryItemId and itineraryId need to match the distributorRef and distributorItemRef, so these four values must also be included in the request body.

  • You must also include a cancelCode - a number corresponding to the reason for cancellation. You can use the <a href="#suggested-cancellation-codes”>suggested cancel codes</a> shown in the table below.

<mark>Note: Post-travel cancellations will not be processed unless a cancel code of 62 or 66 is passed in the cancelCode parameter.</mark>

The /merchant/cancellation service:

Description of JSON request parameters for the /merchant/cancellation service:

ParameterTypeCommentsRequired
itineraryIdintegerViator itinerary reference number
distributorRefstringMerchant partner’s itinerary reference for booking
cancelItemsarrayArray of item to cancel in itinerary
itemIdintegerViator itemId of item to cancel in itinerary
distributorItemRefstringMerchant partner’s itinerary item (booking) reference
cancelCodestringA number indicating the reason for cancelling the booking. A list of <a href="#suggested-cancellation-codes”>suggested cancel codes</a> is shown in the table below.
cancelDescriptionstringNatural-language reason for cancellation. A reason must be provided if a cancelCode of '62' or '66' is passed.✅ for cancelCode '62' or '66'; otherwise ❌

Example /merchant/cancellation request:

In this request, we wish to cancel the booking identified by the following:

ParameterValue
itneraryId12345655
distributorRef"Jdp122"
itemId330056
distributorItemRef"JdpItin001"
cancelCode"82" (Honest mistake - incorrect purchase)

This is accomplished as follows:

API Service

POST /merchant/cancellation

Request body

{
  "itineraryId": 1234655,
  "distributorRef": "Jdp122",
  "cancelItems": [
  {
    "itemId": 330056,
    "distributorItemRef": "JdpItin001",
    "cancelCode": "82"
  }]
}

Example response

{
  "data": {
    "itineraryId": 1234655,
    "cancelItems": [
      {
        "cancellationResponseStatusCode": "Confirmed",
        "cancellationResponseDescription": "No further action required",
        "itemId": 330056,
        "distributorItemRef": "JdpItin001"
      }],
    "distributorRef": "Jdp122"
  },
  "vmid": "221002",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-03-21T14:28:08+0000",
  "errorReference": null,
  "errorMessageText": null,
  "success": true,
  "totalCount": 1,
  "errorName": null
}

<a name=“suggested-cancellation-codes”></a>Suggested cancellation codes:

cancelcodemeaning
'00'Testing (use for test cancellations)
'51'Flight cancellation affecting customer
'52'Flight schedule change unacceptable to customer
'53'Death of the customer or a member of their immediate family
'54'Jury duty/court summons affecting customer
'56'Medical emergency/hospitalization involving the customer or their immediate family
'57'Customer is required for military service
'58'National disaster (insurrection, terrorism, war) affecting the customer
'59'Natural disaster (earthquake, fire, flood) affecting the customer
'62'Post-travel cancellation: the product was cancelled by the supplier and the traveller was not given sufficient notice
'63'Transport strike/labor dispute affecting customer
'66'Post-travel cancellation: the product was not cancelled, but the customer was dissatisfied with the product
'71'Credit card fraud
'72'Car segment cancellation affecting customer
'73'Package segment cancellation affecting customer
'74'Hotel segment cancellation affecting customer
'77'Re-book
'78'Duplicate purchase
'82'Honest mistake (incorrect purchase)
'87'Non-refundable cancellation more than 24 hours prior to travel
'88'Non-refundable cancellation less than 24 hours prior to travel
'98'Customer service/technical support response outside time limit
'99'Duplicate processing

Cancellation errors

If the cancellation was not successful, you will receive an error response.

Example error response

{
  "data": {
    "itineraryId": "3331605", 
    "cancelItems": [{
      "cancellationResponseStatusCode": "Error.ItineraryUnknown", 
      "cancellationResponseDescription": "Please double check the details or contact..."
      "itemId": "600088255",
      "distributorItemRef": "ItinItemRef012"
    }],
    "distributorRef": null 
  },
  "vmid": "221002",
  "errorMessage": null,
  "errorType": null,
  "dateStamp": "2013-03-21T14:43:38+0000", 
  "errorReference": null, 
  "errorMessageText": null,
  "success": true, 
  "totalCount": 1, 
  "errorName": null
}

<a name=“cancellation-response-status-codes-and-their-meanings”></a>Cancellation response status codes and their meanings

cancellationResponseStatusCodeMeaningAction
"Confirmed"The request to cancel and refund the item has been accepted and processedNo further action is required.
"Pending"Confirmation of the request to cancel and refund the item is pending. This only applies when a cancelCode is '62' or '66' was sent and the booking was in a ‘pending’ state.No action required. Partner will be contacted when a decision to confirm/reject has been made by the supplier.
"Rejected"The cancellation request was deniedNo action required. The item cannot be cancelled.
"Error.ItemUnknown"Item not foundDouble-check itemId. Contact Viator Customer Service for more information if required.
"Error.ItineraryUnknown"Itinerary not foundDouble-check itineraryId. Contact Viator Customer Service for more information if required.
"Error.MultipleRequests"Cancellation request contains multiple requestsSubmit only one item per cancellation request.
"Error.NoCancellationCodeOrDescription"Invalid cancelCodecancelCode is invalid – ensure it is two digits long
"Error.Unknown"An undefined error has occurredDouble-check the distributorRef and distributorItemRef. If the error is still occurring, contact the Viator partner support team.

Resubmitting a cancellation request

If the same cancellation request is sent more than once, Viator will respond with the last known response.

Use this page to mock Viator API Documentation &amp; Specification – Merchant Partners in your testing and development.

Run our mock API sample using the open source WireMock library, or in the free edition of WireMock Cloud. You'll have a working API server simulating the behavior of Viator API Documentation &amp; Specification – Merchant Partners, which will allow you to keep building and testing even if the actual API you isn't currently available.

Related mocks

Inventory Management

Maintaining up-to-date inventory for

Geomag API

The World Magnetic Model calculates the

TransitFeeds API

API to view feed information and

Billbee API

Documentation of the Billbee REST API to

OpenCage Geocoder

Worldwide forward and reverse geocoding

Georg API

Ready to accelerate your development flow

Shorter release cycles, more predictable schedules and fewer defects in production.
Start Mocking for Free *Free forever. No credit card needed