Viator APIviator.com ↗
Search Viator tours and activities, resolve destinations, list catalogues, and fetch full experience details. Prices in EUR or USD, content in Italian.
What is the Viator API?
The Viator API exposes 4 endpoints that cover the full experience-discovery workflow on viator.com's Italian catalogue: free-text search, destination resolution, destination catalogue listing, and single-experience detail. Each experience card returns up to 12 fields including product_code, from_price, rating, duration, feature badges, and a photo URL. The get_experience endpoint additionally surfaces the full supplier description, up to 10 photos with captions, and supplier identity.
curl -X GET 'https://api.parse.bot/scraper/6cf39a3c-cb9f-4ba6-a732-ab227196318c/search_experiences?query=Colosseo+sotterranei' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace viator-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Viator SDK — search destinations, browse experiences, fetch details."""
from parse_apis.viator_com_api import Viator, SortOrder, InputNotFound
client = Viator()
# Search for a destination by name, take the first DESTINATION result.
dest = client.destinations.search(query="Roma", limit=5).first()
if dest is None:
raise SystemExit("No destination found")
print(f"Destination: {dest.title} ({dest.parent_name}), id={dest.id}")
# Browse the cheapest experiences in that destination.
for exp in dest.experiences.list(sort=SortOrder.PRICE_LOWEST, limit=3):
print(f" {exp.title} €{exp.from_price.amount} ({exp.duration.min}-{exp.duration.max} {exp.duration.unit})")
# Free-text search with filters, then drill into full details.
hit = client.experience_summaries.search(
query="Colosseo sotterranei",
sort=SortOrder.RATING,
limit=1,
).first()
if hit is not None:
try:
detail = hit.details()
except InputNotFound:
print("Experience no longer available")
else:
print(f"\n{detail.title}")
print(f" Rating: {detail.rating} Reviews: {detail.review_count}")
print(f" {detail.description[:120]}...")
if detail.supplier is not None:
print(f" Supplier: {detail.supplier.name}")
for photo in detail.photos[:3]:
print(f" Photo: {photo.url}")
print("\nexercised: destinations.search / experiences.list / experience_summaries.search / details / experiences.get")
Free-text search of Viator experiences (tours, tickets, activities). Returns one page of experience cards (title, from-price, rating, duration, badges, destination, photo) plus total_results and has_more. Paging is caller-controlled through page (1-based, default 1) and limit (results per page, default 24, max 50; offset = (page-1)*limit). Optional filters narrow the search upstream: features (comma-separated flags), languages (comma-separated ISO 639-1 guide/audio language codes), min_rating (1-5), price_min/price_max (in the requested currency), duration_min/duration_max (minutes). Sort applies to the whole result set. An unknown query returns total_results 0 with an empty experiences array. Results are in Italian; price amounts are in the currency named by the currency field.
| Param | Type | Description |
|---|---|---|
| page | integer | 1-based page number. |
| sort | string | Result ordering. |
| limit | integer | Results per page; values above 50 are clamped to 50. |
| queryrequired | string | Free-text search term, e.g. a place, attraction or activity (one shape: 'Colosseo sotterranei'). |
| currency | string | 3-letter ISO currency code for prices (EUR and USD exercised). |
| features | string | Comma-separated feature flags, any of ON_SALE, FREE_CANCELLATION, LIKELY_TO_SELL_OUT, SKIP_THE_LINE, PRIVATE_TOUR, NEW_ON_VIATOR (e.g. FREE_CANCELLATION,SKIP_THE_LINE). Unknown flags are rejected. |
| languages | string | Comma-separated ISO 639-1 language codes the experience must be offered in, e.g. it,en. |
| price_max | integer | Maximum from-price in the requested currency. |
| price_min | integer | Minimum from-price in the requested currency. |
| min_rating | integer | Minimum average traveller rating, integer 1-5. |
| duration_max | integer | Maximum duration in minutes. |
| duration_min | integer | Minimum duration in minutes. |
{
"type": "object",
"fields": {
"page": "page number returned",
"sort": "sort key applied",
"limit": "page size used",
"query": "echo of the search term",
"currency": "ISO currency code the price amounts are expressed in",
"has_more": "true when page*limit < total_results",
"experiences": "array of experience cards: product_code (string key for get_experience), title, url, brief_description (nullable), from_price {amount, currency}, comparison_price (pre-discount price, nullable), pricing_type, price_varies_by_group_size, rating (0-5, nullable), review_count, duration {min, max, unit MINUTES|HOURS|DAYS}, free_cancellation, likely_to_sell_out, private_tour, new_product, badges (array of badge codes), offered_languages (ISO codes), destination {id, name, parent_name}, photo_url",
"total_results": "integer total matches reported by the site for this query and filters (site caps display at 200+ for broad queries)"
},
"sample": {
"data": {
"page": 1,
"sort": "featured",
"limit": 5,
"query": "Colosseo sotterranei",
"currency": "EUR",
"has_more": true,
"experiences": [
{
"url": "https://www.viator.com/it-IT/tours/Rome/Expert-Guided-Tour-of-Colosseum-Underground-Arena-and-Forum-/d511-55341P7",
"title": "Colosseo e Foro con Arena Opzionale o Accesso Sotterraneo",
"badges": [
"LIKELY_TO_SELL_OUT",
"RECOMMENDED_BY_TRAVELLERS"
],
"rating": 4.7,
"duration": {
"max": 3,
"min": 1,
"unit": "HOURS"
},
"photo_url": "https://dynamic-media.tacdn.com/media/photo-o/34/39/03/2f/caption.jpg?w=1600&h=1000&s=1",
"from_price": {
"amount": 99,
"currency": "EUR"
},
"destination": {
"id": "511",
"name": "Roma",
"parent_name": "Italia"
},
"new_product": false,
"pricing_type": "TRAVELLER_BY_AGE_BAND",
"private_tour": false,
"product_code": "55341P7",
"review_count": 5381,
"comparison_price": null,
"brief_description": "Non tutti i visitatori del Colosseo possono vedere tutte le sue aree.",
"free_cancellation": true,
"offered_languages": [
"de",
"en",
"es",
"fr",
"it",
"pt"
],
"likely_to_sell_out": true,
"price_varies_by_group_size": true
}
],
"total_results": 173
},
"status": "success"
}
}About the Viator API
Searching and Resolving Destinations
The search_destinations endpoint accepts a place name in Italian or English and returns typed suggestions. Results carry a type field — either DESTINATION (city, region, or country) or DESTINATION_TAG (a category label). DESTINATION rows include a destination_id string that feeds directly into list_destination_experiences. This two-step flow — resolve first, then list — mirrors the site's own navigation pattern.
Browsing a Destination's Catalogue
Passing a destination_id to list_destination_experiences returns paginated experience cards for that location. The fixed page size is 24 cards per request; total_pages and total_results indicate catalogue depth, and has_more simplifies loop termination. The destination object in the response gives name, city_name, country_name, and parent_name context. The sort parameter controls ordering and the currency parameter (EUR and USD exercised) governs all from_price amounts.
Free-Text Search
The search_experiences endpoint accepts an arbitrary query — an attraction name, activity type, or place — and returns experience cards with title, brief_description, from_price, rating, duration, badges, and photo. Results are capped server-side at 200+ for broad queries. The caller can narrow results using features (comma-separated flags: FREE_CANCELLATION, SKIP_THE_LINE, LIKELY_TO_SELL_OUT, ON_SALE, PRIVATE_T), languages (ISO 639-1 codes), price_max, sort, and limit (max 50 per page).
Single Experience Detail
The get_experience endpoint accepts a product_code from any card and returns the full record: title, description, from_price, rating, duration, supplier (name and code), photo_count, and up to 10 photos each with a url and caption. An unrecognised product_code returns a not-found error. The currency parameter applies to the from_price amount here as in all other endpoints.
The Viator API is a managed, monitored endpoint for viator.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when viator.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official viator.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build an Italian-language activity finder that surfaces Viator tours filtered by FREE_CANCELLATION and sorted by rating.
- Aggregate from_price data across destination catalogues to compare activity costs between cities.
- Populate a travel itinerary planner with experience duration, photos, and descriptions from get_experience.
- Resolve user-typed place names to destination_ids for downstream catalogue queries via search_destinations.
- Create an alert system that monitors from_price changes for a saved list of product_codes.
- Build a city-guide app that lists all available experiences for a destination using list_destination_experiences with sorting by popularity.
- Filter SKIP_THE_LINE and PRIVATE_T experiences for high-demand attractions to surface premium options to users.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Viator have an official developer API?+
What does search_experiences return beyond a basic title and price?+
experiences array includes product_code (the key for get_experience), title, url, brief_description (nullable), from_price with amount and currency, an average rating, a duration object with min/max/unit, badges (e.g. LIKELY_TO_SELL_OUT, FREE_CANCELLATION), the destination name, and a photo URL. You can also filter the result set by features, languages, and price_max at query time.Does the API return availability calendars or booking slots?+
What are the pagination limits for list_destination_experiences?+
page parameter (1-based) to step through pages. The response provides total_pages, total_results, and has_more so your loop can terminate cleanly without an extra probe request.Does the API cover Viator's non-Italian locales (English, French, German, etc.)?+
currency parameter. You can fork this API on Parse and revise it to point at a different locale if your application requires another language.