Here is what we are building: a script that takes a region and trip style from the command line, fetches a structured itinerary from the TheWineTrip API, passes it to Claude with a prompt, and returns a conversational trip plan. Two API calls. About 60 lines of Python. The interesting part is what comes out.
Why This Works Better Than Asking Claude Directly
Ask Claude to "plan a 4-day Barossa Valley wine trip" with no external data and it produces a confident-sounding response based on training data. The winery names are plausible. The driving times are fabricated. Some producers it recommends may have closed or changed their tasting model. The quality of the output degrades in proportion to how specific the question is.
Passing structured, current API data into the context window solves this. Claude stops guessing and starts synthesising real information — real winery names, real sub-regional notes, real harvest timing, real accommodation tiers. The output is grounded.
Prerequisites
You need Python 3.9+ and two packages:
```bash pip install requests anthropic ```
For the Anthropic SDK, get an API key at [console.anthropic.com](https://console.anthropic.com). The TheWineTrip API is free with no key required on the free tier (100 requests/day).
Step 1: Fetch the Itinerary
The `/api/v1/plan` endpoint returns a fully structured trip plan in one call:
```python import requests
def get_wine_trip_plan(region: str, days: int, style: str) -> dict: resp = requests.get( "https://thewinetrip.com/api/v1/plan", params={"region": region, "days": days, "style": style}, timeout=10 ) resp.raise_for_status() return resp.json() ```
The response contains `plan.itinerary` (day-by-day schedule), `plan.mustVisitWineries` (curated list with GPS), `plan.accommodation` (budget/mid/luxury tiers), `plan.budget` (daily cost estimate), and `region` metadata (harvest calendar, wine styles, getting-there notes).
Step 2: Build the Context for Claude
Serialise the plan data into a clear text block for the LLM:
```python import json
def build_context(plan_data: dict) -> str: region = plan_data["region"] plan = plan_data["plan"] wineries = [w["name"] for w in plan["mustVisitWineries"]]
return f"""Wine region: {region["name"]} ({region["country"]}) Best months: {", ".join(region["bestMonths"])} Wine styles: {", ".join(region["wineStyles"])}
{plan["days"]}-day {plan["style"]} itinerary: {json.dumps(plan["itinerary"], indent=2)}
Must-visit wineries: {", ".join(wineries)}
Accommodation: Budget: {plan["accommodation"]["budget"]} Mid-range: {plan["accommodation"]["mid"]} Luxury: {plan["accommodation"]["luxury"]}
Estimated daily budget: {json.dumps(plan["budget"], indent=2)} """ ```
Step 3: Pass to Claude and Get the Response
```python import anthropic
def generate_trip_summary(context: str, style: str) -> str: client = anthropic.Anthropic()
message = client.messages.create( model="claude-opus-4-7", max_tokens=1024, messages=[ { "role": "user", "content": f"""You are a wine travel expert. Using only the structured data below, write a practical, engaging trip summary for a {style} traveller. Be specific — use the real winery names and accommodation options provided. Do not add wineries, costs, or facts not present in the data.
{context}""" } ] ) return message.content[0].text ```
Step 4: Wire It Together
```python import sys
def main(): region = sys.argv[1] if len(sys.argv) > 1 else "bordeaux" days = int(sys.argv[2]) if len(sys.argv) > 2 else 4 style = sys.argv[3] if len(sys.argv) > 3 else "romantic"
print(f"Fetching {days}-day {style} trip for {region}...") plan_data = get_wine_trip_plan(region, days, style)
context = build_context(plan_data) summary = generate_trip_summary(context, style)
print("\n" + "=" * 60) print(summary)
if __name__ == "__main__": main() ```
Run it:
```bash python wine_recommender.py barossa 4 luxury python wine_recommender.py burgundy 5 serious python wine_recommender.py douro 3 romantic ```
What the Output Looks Like
For `barossa 3 romantic`, Claude receives the actual Barossa itinerary data — day-by-day schedule, winery list including Seppeltsfield and Torbreck, accommodation tiers from A$150 budget to A$400 luxury — and produces a response grounded in those facts. The winery names match what's in the database. The accommodation suggestions match the tiers. The harvest timing matches the API's climate data.
Without the API context, Claude would produce confident generalities about "the sun-drenched Barossa floor" with winery names pulled from training data — some accurate, some stale. With the context, every specific claim can be traced back to the data.
What to Build Next
**Save the trip.** Once you have a plan, POST the parameters to `/api/save-trip` and get back a shareable URL at `/trip/{id}`. Add this link to the Claude response.
**Add winery search.** Call `/api/v1/wineries?region={slug}&q={name}` to let users search for specific producers and include them in the context window alongside the generated itinerary.
**Make it conversational.** Use Claude's multi-turn API to let users refine the plan: "make day 2 more budget-friendly", "add more time in Eden Valley", "what should I do if it rains on day 3?". The context stays stable; the user iterates.
**Deploy it as an API.** Wrap the script in FastAPI or a Next.js route and add it to your travel app as an endpoint. The free tier handles 100 requests/day; Pro handles 10,000.
The full OpenAPI spec is at [/api-docs](/api-docs). The developers page at [/developers](/developers) has the rate limit details and Pro upgrade.