Culture Trip APIculturetrip.com ↗
Access Culture Trip travel articles, destination guides, bookable trip listings, and pricing via 7 structured API endpoints. Filter by region, city, or keyword.
What is the Culture Trip API?
The Culture Trip API exposes 7 endpoints covering travel articles, destination guides, and bookable trip data from culturetrip.com. Use get_articles_by_destination to pull article titles, URLs, thumbnails, and categories for any destination path, or use list_trips to retrieve bookable tour cards with names, prices, durations, and booking links. The API also resolves trip pricing details and surfaces popular cities and regional destination hierarchies.
curl -X GET 'https://api.parse.bot/scraper/baadb9bd-2400-44f7-905e-69a16378a62a/get_articles_by_destination?destination_path=%2Fasia%2Fjapan%2Ftokyo' \ -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 culturetrip-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.
"""
Culture Trip API Client
Get your API key from: https://parse.bot/settings
Practical example: Discover travel destinations, read articles, and find bookable trips.
"""
import os
import requests
from typing import Optional
from urllib.parse import urlparse
class ParseClient:
"""Client for Culture Trip API via Parse Bot."""
def __init__(self, api_key: Optional[str] = None):
"""Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "baadb9bd-2400-44f7-905e-69a16378a62a"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key must be provided or set in PARSE_API_KEY environment variable")
def _call(self, endpoint: str, method: str = "POST", **params) -> dict:
"""Make an API call to the Parse Bot scraper.
Args:
endpoint: The endpoint name (e.g., 'get_articles_by_destination')
method: HTTP method - 'GET' or 'POST'
**params: Parameters to send with the request
Returns:
Response JSON as dictionary
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
try:
if method.upper() == "GET":
response = requests.get(url, headers=headers, params=params)
else: # POST
response = requests.post(url, headers=headers, json=params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
raise
def search_trips(self, query: str) -> dict:
"""Search for travel locations and get suggestions.
Args:
query: Search keyword (e.g., London, Kyoto)
Returns:
Dictionary with suggestions list
"""
return self._call("search_trips", method="GET", query=query)
def list_destinations_by_region(self, region: str) -> dict:
"""List countries and cities within a specific region.
Args:
region: Region slug (e.g., asia, europe, south-america)
Returns:
Dictionary with destinations list
"""
return self._call("list_destinations_by_region", method="GET", region=region)
def get_articles_by_destination(self, destination_path: str) -> dict:
"""Retrieve a list of travel articles for a specific destination path.
Args:
destination_path: The URL path of the destination (e.g., /asia/japan/tokyo)
Returns:
Dictionary with articles list
"""
return self._call("get_articles_by_destination", method="GET", destination_path=destination_path)
def get_article_detail(self, article_path: str) -> dict:
"""Retrieve full details of a specific article including curated attractions.
Args:
article_path: The URL path of the article
Returns:
Dictionary with article details including title, content, author, attractions
"""
return self._call("get_article_detail", method="GET", article_path=article_path)
def list_trips(self, destination: Optional[str] = None) -> dict:
"""List bookable trips for a given destination.
Args:
destination: Destination slug (e.g., japan, anywhere)
Returns:
Dictionary with trips list
"""
params = {}
if destination:
params["destination"] = destination
return self._call("list_trips", method="GET", **params)
def get_trip_dates_and_prices(self, trip_url: str) -> dict:
"""Get pricing information for a specific trip.
Args:
trip_url: Full URL of the trip page
Returns:
Dictionary with trip details including tour_id, price, currency
"""
return self._call("get_trip_dates_and_prices", method="GET", trip_url=trip_url)
def get_popular_cities(self) -> dict:
"""Get popular cities highlighted on the site.
Returns:
Dictionary with popular cities list
"""
return self._call("get_popular_cities", method="GET")
def extract_path_from_url(url: str) -> str:
"""Extract the path component from a full URL."""
parsed = urlparse(url)
return parsed.path
def main():
"""Practical workflow: Discover destination, read articles, find and price trips."""
client = ParseClient()
print("\n" + "=" * 70)
print("CULTURE TRIP TRAVEL DISCOVERY TOOL")
print("=" * 70)
# Step 1: Get popular cities to start exploration
print("\n[1] Fetching popular cities from the homepage...")
try:
popular = client.get_popular_cities()
if popular.get("data", {}).get("cities"):
cities = popular["data"]["cities"]
print(f"✓ Found {len(cities)} popular cities")
for idx, city in enumerate(cities[:3], 1):
print(f" {idx}. {city['name']}")
except Exception as e:
print(f"✗ Error fetching popular cities: {e}")
return
# Step 2: Search for a specific destination
search_query = "Kyoto"
print(f"\n[2] Searching for '{search_query}'...")
try:
search_results = client.search_trips(search_query)
suggestions = search_results.get("data", {}).get("suggestions", [])
print(f"✓ Found {len(suggestions)} search suggestions")
for idx, sugg in enumerate(suggestions[:3], 1):
print(f" {idx}. {sugg['displayName']} ({sugg['type']})")
if not suggestions:
print("✗ No suggestions found, cannot continue")
return
# Select the first suggestion (usually the most specific match)
selected = suggestions[0]
destination_url = selected["url"]
destination_name = selected["displayName"]
print(f"\n→ Selected: {destination_name}")
except Exception as e:
print(f"✗ Error searching: {e}")
return
# Step 3: Get articles for the selected destination
print(f"\n[3] Fetching travel articles for {destination_name}...")
try:
articles_response = client.get_articles_by_destination(destination_url)
articles = articles_response.get("data", {}).get("articles", [])
print(f"✓ Found {len(articles)} articles")
if not articles:
print("✗ No articles found")
return
# Step 4: Get detailed information for each article
print(f"\n[4] Reading article details (showing first 2)...")
article_details_list = []
for idx, article in enumerate(articles[:2], 1):
print(f"\n Article {idx}: {article['title']}")
print(f" Category: {article['category']}")
try:
# Extract path from full URL
article_path = extract_path_from_url(article["url"])
detail_response = client.get_article_detail(article_path)
detail_data = detail_response.get("data", {})
if detail_data:
article_details_list.append(detail_data)
if detail_data.get("author"):
print(f" Author: {detail_data['author']}")
if detail_data.get("publish_date"):
print(f" Published: {detail_data['publish_date']}")
if detail_data.get("content"):
preview = detail_data["content"][:120].strip() + "..."
print(f" Preview: {preview}")
# List featured attractions
attractions = detail_data.get("attractions", [])
if attractions:
print(f" Featured attractions ({len(attractions)} total):")
for att_idx, attraction in enumerate(attractions[:2], 1):
print(f" • {attraction['name']}")
except Exception as e:
print(f" ⚠ Could not fetch full article details: {e}")
except Exception as e:
print(f"✗ Error fetching articles: {e}")
return
# Step 5: Find bookable trips for the destination
print(f"\n[5] Searching for bookable trips...")
try:
trips_response = client.list_trips("japan")
trips = trips_response.get("data", {}).get("trips", [])
print(f"✓ Found {len(trips)} available trips")
if not trips:
print(" No trips available")
else:
# Step 6: Get detailed pricing for each trip
print(f"\n[6] Getting pricing details (showing first 2)...")
for idx, trip in enumerate(trips[:2], 1):
print(f"\n Trip {idx}: {trip['name']}")
print(f" Base Price: {trip['price']}")
print(f" Duration: {trip['duration']}")
try:
pricing_response = client.get_trip_dates_and_prices(trip["url"])
pricing_data = pricing_response.get("data", {})
if pricing_data:
price = pricing_data.get("price", "N/A")
currency = pricing_data.get("currency", "USD")
tour_id = pricing_data.get("tour_id", "N/A")
print(f" Exact Price: {price} {currency}")
print(f" Tour ID: {tour_id}")
except Exception as e:
print(f" ⚠ Could not fetch pricing: {e}")
except Exception as e:
print(f"✗ Error fetching trips: {e}")
# Step 7: Explore other destinations by region
print(f"\n[7] Exploring other destinations in Asia...")
try:
region_response = client.list_destinations_by_region("asia")
destinations = region_response.get("data", {}).get("destinations", [])
print(f"✓ Found {len(destinations)} destinations in Asia:")
for idx, dest in enumerate(destinations[:5], 1):
print(f" {idx}. {dest['name']}")
except Exception as e:
print(f"✗ Error fetching region data: {e}")
print("\n" + "=" * 70)
print("EXPLORATION COMPLETE")
print("=" * 70 + "\n")
if __name__ == "__main__":
main()Retrieve a list of travel articles for a specific destination path. Returns articles with titles, URLs, thumbnails, and categories found on the destination page.
| Param | Type | Description |
|---|---|---|
| destination_pathrequired | string | The URL path of the destination on theculturetrip.com (e.g., /asia/japan/tokyo, /europe/united-kingdom/england/london, /asia/japan). |
{
"type": "object",
"fields": {
"articles": "array of article objects with title, url, thumbnail, and category"
},
"sample": {
"data": {
"articles": [
{
"url": "https://theculturetrip.com/asia/japan/tokyo/articles/best-things-to-see-and-do-in-tokyo",
"title": "The 24 Best Things to See and Do in Tokyo",
"category": "Planning - Overview",
"thumbnail": "https://cdn-v2.theculturetrip.com/10x/wp-content/uploads/2024/06/jezael-melgoza-fydgzecukk0-unsplash-e1718892069733.webp?quality=1"
}
]
},
"status": "success"
}
}About the Culture Trip API
Articles and Destination Content
The get_articles_by_destination endpoint accepts a destination_path string (e.g., /asia/japan/tokyo) and returns an array of article objects, each containing a title, url, thumbnail, and category. For deeper content, get_article_detail takes an article_path and returns the full article content (up to 5,000 characters), author, publish_date in ISO 8601 format, and a structured attractions array — each attraction carries a name, description, and image URL.
Trip Discovery and Pricing
search_trips accepts a freeform query string and returns suggestions with displayName, url, and a geographic type such as Country or Continent. list_trips accepts an optional destination slug (e.g., japan, asia/thailand) and returns trips arrays with name, price, duration, thumbnail, and a url pointing to the booking page on tourhub. To get live pricing detail for a specific tour, pass that tourhub URL to get_trip_dates_and_prices, which resolves to a tour_name, price, currency, and tour_id.
Regional and City Navigation
list_destinations_by_region takes a region slug — valid values include asia, europe, south-america, africa, pacific, north-america, and middle-east — and returns an array of destination name and path pairs. get_popular_cities requires no inputs and returns a flat list of city name and path values pulled from the Culture Trip homepage.
The Culture Trip API is a managed, monitored endpoint for culturetrip.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when culturetrip.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 culturetrip.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?+
- Aggregate curated travel articles by destination path for a city guide app using
get_articles_by_destination. - Build a trip comparison tool by fetching bookable tours with prices and durations from
list_tripsfiltered by destination slug. - Populate an attractions database by extracting the
attractionsarray (name, description, image) fromget_article_detail. - Implement a destination autocomplete feature using
search_tripsto return typed location suggestions with URLs. - Construct a regional destination index by iterating
list_destinations_by_regionacross all supported region slugs. - Display live tour pricing by resolving tourhub URLs through
get_trip_dates_and_pricesto getprice,currency, andtour_id. - Seed a homepage 'popular cities' widget using the city names and paths returned by
get_popular_cities.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Culture Trip offer an official developer API?+
What does `get_article_detail` return beyond the article text?+
title, author, publish_date (ISO 8601), and content (truncated to 5,000 characters), plus an attractions array. Each attraction object includes a name, description, and image URL, making it useful for building curated points-of-interest lists from editorial content.Does `list_trips` support filtering by price range or trip duration?+
list_trips accepts only an optional destination slug and returns all matching trips with their price and duration fields included in the response. Client-side filtering by those fields is straightforward. You can fork this API on Parse and revise it to add server-side price or duration filter parameters.Is user-generated content like reviews or ratings available?+
How specific can the `destination_path` be in `get_articles_by_destination`?+
/asia/japan/tokyo) or as broad as a country or region (e.g., /europe/united-kingdom/england). Results reflect the articles listed at that path level, so broader paths typically return a wider article set.