The Viator API allows for two general approaches to managing products and availability – storing the Viator product content and availability schedules in a local database; or retrieving product details and availability in real-time. Please note that it is necessary to contact the API onboarding team at affiliateapi@tripadvisor.com prior to starting development, and present the ingestion plan for approval.

In this guide, we cover:

Ingestion model: Product and availability ingestion with */modified-since endpoints

Search model: Real-time requests with /products/search and individual-product-content endpoints

Ingesting auxiliary data (tags, destinations, locations, booking questions, attractions, reviews)

Z

Requirements and best practices

Pros and cons of Ingestion and Search models

Product and availability ingestion with modified-since endpoints

s

Please note: If you’re a basic-access affiliate API partner, you won’t have access to the */modified-since endpoints. The Access to Endpoints section of our API documentation describes endpoint access for different partner types. If you’d like to change your partnership category such that you have full API access, please contact us at affiliateapi@tripadvisor.com.

If you are maintaining a local database of our product catalog, you must firstly ingest and then periodically refresh both the product content and availability schedules data. The API offers two */modified-since endpoints for content ingestion:

Ingesting Viator’s complete product and availability catalog

1

Make a request to the /products/modified-since or /availability/schedules/modified-since endpoint, with no values supplied for the modified-since or cursor parameters.

GET https://api.sandbox.viator.com/partner/products/modified-since?count=500
{

“products”: [

{},

], “nextCursor”: “MTU3NDA0MzU1NQ==”

}
2

Make a subsequent request to the endpoint, with the cursor parameter set to the value of the nextCursor element returned by your previous request.

https://api.sandbox.viator.com/partner/products/modified-since?count=500&cursor=MTU3NDA0MzU1NQ==
{

“products”: [

{},

],
“nextCursor”: AJKSHDJKKJhaskaSJHK==

}

3

Continue to make requests with the cursor parameter set to the value of the nextCursor element returned by the previous request. Eventually, a request will return no data in the products element, and will not include a nextCursor value. This indicates that all products have been returned. To optimize ingestion time, we recommend setting the count parameter to it’s maximum value of 500 for each request.

Refreshing your local product and availability catalogue

1

Make a request to the /products/modified-since or /availability/schedules/modified-since endpoint, with the cursor parameter set to the value of the most recent nextCursor element returned by a request to the same endpoint. This value may be found in the response to your second to last such request.

2

Continue to make requests with the cursor parameter set to the value of the nextCursor element of the previous request, until a request again does not include a nextCursor value.

3

To periodically refresh your database, repeat steps one and two in a regular cadence.

Please note:

  • When ingesting and refreshing either the product content or availability schedules, the same conventions are applied. It is important that product ingestion and availability ingestion are performed as separate processes, as nextCursor elements are not compatible between the two endpoints.
  • The ingestion model above doesn’t include the modified-since parameter. That’s because we strongly recommend using the cursor-based method, as in doing so the risk of missing any product updates is eliminated. If you do find a need to use the modified-since parameter, it’s essential to express the time in UTC, apply the correct timestamp format, and make sure it’s URL-encoded.
  • The /products/bulk and /availability/schedules/bulk endpoints must not be used as your mainstay for ingesting all product and availability data. These endpoints should be used only on an ad-hoc basis in order to refresh the details of a specific subset of products, should that need arise – and that might be never. The modified-since endpoints were designed specifically to support a much more efficient delta-update workflow that eliminates the possibility of making unnecessary update requests for products that have not been updated.

Real-time requests with /products/search and single product endpoints

API partners that do not want to ingest product and availability data can use the /products/search endpoint in order to retrieve products from a particular destination based on the desired search criteria, such as:

  • products linked to an attraction
  • availability (start date and end date)
  • free cancellation
  • skip the line
  • private tour
  • special offer
  • highest / lowest price
  • likely to sell out
  • tags related to product category or specific product features (read more about Viator tags in: Viator tags, explained)
  • confirmationType
  • durationInMinutes
  • rating
  • new on Viator
  • Viator exclusive
It’s possible to select the sort order applied to results – with the following options:
  • “DEFAULT” – based on the “featured” sort order from Viator (Note: What Viator gets paid impacts this sort order).
  • “PRICE” – sorting by price (fromPrice) with two options for order: ASCENDING (default), DESCENDING.
  • “TRAVELER_RATING” – sorting by average product rating (“DESCENDING” order)
  • “ITINERARY_DURATION” – sorting by tour or activity duration (in minutes)
  • “NEW_ON_VIATOR” – sorting by the date the product was created ( “ASCENDING” order)
The /products/search request could look like this:
Example request to /products/search

{

“filtering”: {

“destination”: “77”,
“tags”: [

21972

],
“flags”: [“FREE_CANCELLATION”, “PRIVATE_TOUR”, “SPECIAL_OFFER”],
“lowestPrice”: 50,
“highestPrice”: 500,
“startDate”: “2022-09-20”,
“endDate”: “2022-09-24”

},
“sorting”: {

“sort”: “PRICE”,
“order”: “DESCENDING”

},
“pagination”: {

“start”: 1,
“count”: 5

},
“currency”: “USD”

}

If you’re displaying product content from the API in real time, you won’t be able to rely solely on the limited product data retrievable from the /products/search endpoint to get all product details. For example, neither the itinerary, inclusions and exclusions, which age-bands are allowed to book, the booking questions that must be answered at the time the booking request is sent, the pickup locations available for the product, nor the cancellation policy are available in /products/search response. You will need to retrieve the remaining product information from the product-specific content endpoint – /products/{product-code} – in real-time. This endpoint should be called only for the selected product and only when the customer is moving from the search page to the product display page and updated product information is required.

If you’d like to create a calendar view showing all the dates on which the product is available, you can retrieve the necessary data with the /availability/schedules/{product-code} endpoint. Only once the travel date and passenger mix are selected can you effectively use the /availability/check endpoint to verify the product’s availability and pricing for the present moment.

Please note:

Ingesting auxiliary data (applies to ingestion partners and search partners)

s

If you are a search partner, you don’t have to ingest all location data and reviews if you don’t have the ability to do so. You are allowed to verify details of locations and reviews linked to the selected product in real-time. Please bear in mind that the review content cannot be indexed as it’s a protected proprietary information (see Key concepts – Protecting unique content)

It is important to ensure that tags, destinations, locations, attractions, booking questions, cancellation reasons, reviews and photos are stored locally in your system and are kept up-to-date, as these values change periodically. For example, a new tag could be added or an existing location could be updated or removed. If you allow your local data to fall out of sync with its source of truth, you could run into errors when trying to make bookings.

To avoid any errors, you need to have two processes in place:

1

Fixed-cadence full updates

When an existing destination or location has had its details updated, the change will not be evident from the product content response as these data elements are communicated via reference. A full data refresh is required to identify if any changes have been made. This applies to all endpoints that de-reference referenced information (destination Id, location reference, tag, attraction Id) or other data that isn’t returned in the /products/modified-since response. We recommend implementing the following fixed-cadences at which to perform full updates from these endpoints:

* This endpoint is used for ingestion of reviews as well as traveler photos.

** When retrieving the location details associated with particular location references using /locations/bulk, please make sure that you do not exceed the maximum number of location references allowed in each request (500). If exceeded, a “BAD_REQUEST” error will be returned in the response with the message “Maximum number of locations 500 exceeded”.

2

On-demand updates

In addition to the fixed-cadence full updates, it is necessary to conduct on-demand updates for any new data encountered in the API.

You should establish logic that identifies when new data is encountered during ingestion with the /products/modified-since endpoint. For example, in case of a novel location reference get the details of that location using the /locations/bulk endpoint. There is no need to refresh all locations in this scenario as this will be carried out during the scheduled monthly refresh of location data.

On demand updates should be conducted as follows:

Endpoint When to update
/exchange-rates

Whenever you encounter a currency that you need to convert, but the last-retrieved exchange-rate for that currency-pair is no longer valid due to having expired (according to the expiry value in the response from this endpoint)

/locations/bulk*

Whenever you encounter a location reference code that you do not yet have the details for (we recommend retrieving location details in batches using this endpoint; therefore, the retrieval of new location data can commence after all new product content is retrieved)

/products/tags

Whenever you encounter a tag reference code that you do not yet have the details for

/v1/taxonomy/destinations

Whenever you encounter a destination id that you do not yet have the details for

/products/booking-questions

Whenever you encounter a booking question identifier that you do not yet have the details for

/v1/taxonomy/attractions

Whenever you encounter an attraction identifier that you do not yet have the details for

/reviews/product

If the number of reviews available for a product, which is reported in the reviews.totalReviews element in the product content response, has changed compared with its previous value, the reviews for that product should also be refreshed by calling the /reviews/product endpoint. We request that you rate-limit your use of this service to 30 requests per minute.

* When retrieving the location details associated with particular location references using /locations/bulk, please make sure that you do not exceed the maximum number of location references allowed in each request (500).

It is especially important in case of exchange rates to retrieve updates based on the expiry timestamp returned in the response from /exchange-rates to ensure that the correct pricing is always applied:

Example request to /products/search

{

“rates”: [

{

“sourceCurrency”: “USD”,
“targetCurrency”: “GBP”,
“rate”: 0.83185425422550000000,
“lastUpdated”: “2022-06-29T07:00:09Z”,
“expiry”: “2022-07-01T07:05:09Z”

},
{

“sourceCurrency”: “BRL”,
“targetCurrency”: “GBP”,
“rate”: 0.15986489621000000000,
“lastUpdated”: “2022-06-29T07:00:08Z”,
“expiry”: “2022-07-01T07:05:08Z”

}

]

}

The exchange rates used in – and available from – the API are updated daily; therefore, you only need to call the /exchange-rates endpoint once per day (based on the expiry timestamp) and apply the conversion rates returned in the response to all products.

For more information, see the Update frequency section of our API documentation.

Please note: If you are a partner that uses the /products/search endpoint, you don’t have to ingest all location data and reviews if you don’t have the ability to do so. You are allowed to verify details of locations and reviews linked to the selected product in real-time. Please bear in mind that the review content cannot be indexed as it’s a protected proprietary information (see Key concepts – Protecting unique content)

Requirements and best practices

Z

Requirements

  1. After you ingest all product content and availability schedules, do not attempt to re-ingest the full catalog on each ingestion cycle. This will reduce the load on our systems, and improve your ingestion time.
  2. Schedule product and availability ingestion cycles at a cadence not higher than once hourly (we recommend updates as frequently as possible, especially for availability and pricing).
  3. Don’t use single product and availability endpoints (/products/{product-code} and /availability/schedules/{product-code}) for ingestion.
  4. Don’t use the /products/bulk and /availability/schedules/bulk endpoints for ingestion of all product and availability data. These endpoints should be used only on an adhoc basis in order to verify details of selected products.
  5. Never use /availability/check to ingest schedules or future availability. This endpoint may only be used to check live availability on a per-product basis once a passenger mix and travel date have been selected.
  6. If you are converting prices from our supplier’s currency into your desired currency, limit requests to the /exchange-rates endpoint to once daily based on the expiry timestamp. These conversion rates should be applied to all products in the specified currency until the next refresh cycle.
  7. Ingest tags, locations, destinations, booking questions, cancellation reasons, attraction and reviews data and conduct fixed-cadence full updates of this data as well as on-demand updates (see recommendations from section 3).

Best practices

  1. If you would like to exclude certain products or product types, you can do so at the time of ingestion. When ingesting products, assess whether the product contains undesired attributes and filter out the product (do not store it).
  2. You should only ingest schedules for the products you have ingested – that is, if you have excluded products from the product ingestion, you should not ingest the availability schedules for those products. You can filter on ingestion by discarding information for products not ingested.
  3. You should not use the /products/search endpoint for ingestion as you may not be able to get all products this way (10k limit on how far you can paginate). You won’t get all data as search has a summary model and there is a limit of 50 results per request.

Please note that it is necessary to contact the API onboarding team at affiliateapi@tripadvisor.com prior to starting development, and present the ingestion plan for approval.

Pros and Cons of Ingestion v. Search

Ingestion model Search model
Pros
  • Efficient data ingestion and data management
  • Additional customization and filtering options
  • Reduced reliance on real-time API responses
  • Typically requires less development work
  • Built in product filtering and sorting options
  • Lower cost of data storage

 

Cons
  • Typically requires more development work
  • Cost of data storage
  • Limited customization options
  • Full reliance on the API