Trip page and calendar
The trip
Section titled “The trip”GET /v1/public/products/{product} takes the trip’s slug or id and
answers everything its page shows: text, photos in order (the first is the
cover), highlights, the itinerary, inclusions, places, the seller, the
options with their units and policies, and the extras.
curl "https://api.stg.vacationpackagesoman.com/v1/public/products/desert-safari-with-bbq-dinner?locale=en" \ -H "Tp-Publishable-Key: $TP_KEY"const res = await fetch("https://api.stg.vacationpackagesoman.com/v1/public/products/desert-safari-with-bbq-dinner?locale=en", { headers: { "Tp-Publishable-Key": process.env.TP_KEY!, },})const answer = await res.json()Answer: 200 OK (shortened)
{ "id": "5b1f0c3e-8d2a-4f6b-9c41-2e7a9d0b6f13", "slug": "desert-safari-with-bbq-dinner", "content_locale": "en", "locales": [ "en", "ar" ], "title": "Desert safari with BBQ dinner", "timezone": "Asia/Dubai", "sales_paused": false, "options": [ { "id": "9e4c2a71-3b5d-4e8f-a1c6-7d20f5b93e48", "name": "Shared 4WD, afternoon", "is_default": true, "private": false, "vehicle": "Shared 4WD", "sales_paused": false, "min_units": null, "max_units": null, "availability_type": "start_time", "capacity_mode": "limited", "confirmation": "instant", "units": [ { "id": "1c7e9b42-6a3f-4d85-b0e2-58f4a1c9d736", "type": "adult", "label": "Adult", "min_age": 12, "max_age": null, "min_qty": null, "max_qty": null, "takes_seat": true, "free": false }, { "id": "2d8fac53-7b40-4e96-81f3-69a5b2dae847", "type": "child", "label": "Child (3-11)", "min_age": 3, "max_age": 11, "min_qty": null, "max_qty": null, "takes_seat": true, "free": false } ], "policy": { "name": "Flexible", "tiers": [ { "from_days": 1, "to_days": null, "refund_pct": 100 }, { "from_days": 0, "to_days": 0, "refund_pct": 0 } ] }, "traveller_details": { "scope": "lead", "fields": [], "collect": "checkout", "due_hours_before": null }, "pickup": null, "pickup_rules": [] } ], "city": { "slug": "dubai", "name": "Dubai" }, "region": { "slug": "dubai-emirate", "name": "Dubai" }, "country": { "slug": "ae", "name": "United Arab Emirates" }, "seller": { "slug": "demo", "name": "tourpingo demo", "base": "Nowhere: a demo for developers", "blurb": "Invented trips in the UAE, Oman and Zanzibar for trying tourpingo's API. Never on the marketplace; bookings are deleted after a day." }, "extras": [ { "id": "3e90bd64-8c51-4fa7-92a4-7ab6c3ebf958", "name": "Quad bike, 30 minutes", "description": null, "per": "item", "who": "choose", "included": false, "option_ids": [], "min_age": 16, "max_age": null, "unit_types": [], "max_per_booking": null, "pay": "upfront", "price": { "amount": 4000, "currency": "USD" }, "unit_prices": {}, "local_price": null } ], "from_price": { "amount": 6500, "currency": "USD", "group_size": 1 }}- Ask with
localefor the page’s language andcurrencyfor its prices.content_localesays which language the text is in (languages). - On a marketplace, add
sellerto open a trip by its slug. - A trip the site doesn’t sell, or doesn’t have, is
404 NotFound. sales_pausedon the trip or an option: show it, but don’t offer to book.
Choosing an option
Section titled “Choosing an option”When a trip has several options, show each with what sets it apart: its
name, whether it is private, its vehicle, its policy and its units.
Start with the one marked is_default.
The calendar
Section titled “The calendar”Each option has its own calendar. Ask for a month at a time:
curl "https://api.stg.vacationpackagesoman.com/v1/public/options/9e4c2a71-3b5d-4e8f-a1c6-7d20f5b93e48/calendar?month=2026-11" \ -H "Tp-Publishable-Key: $TP_KEY"const res = await fetch("https://api.stg.vacationpackagesoman.com/v1/public/options/9e4c2a71-3b5d-4e8f-a1c6-7d20f5b93e48/calendar?month=2026-11", { headers: { "Tp-Publishable-Key": process.env.TP_KEY!, },})const answer = await res.json()Answer: 200 OK (shortened)
[ { "date": "2026-11-13", "status": "sold_out", "starts": [ { "time": "15:00", "status": "sold_out", "remaining": 0 } ] }, { "date": "2026-11-14", "status": "open", "starts": [ { "time": "15:00", "status": "open", "remaining": 14 } ] }, { "date": "2026-11-15", "status": "closed", "starts": [] }]Show open days as bookable, and for each start its time and, when
counted, the places left. sold_out, closed and past_cutoff days
aren’t bookable. The calendar has no prices: once the traveller picks a
day, ask for a quote.
Pickup
Section titled “Pickup”An option with pickup collects travellers where they stay. Its
pickup_rules list the areas it covers and their prices, for the page.
For one traveller’s address, search the places library as they type with
GET /v1/public/places/search, then ask the option with
GET /v1/public/options/{optionId}/pickup/resolve, which says whether
pickup is offered there, when and at what price. Send the chosen place
with the quote as pickup.
Show the seller
Section titled “Show the seller”The trip’s seller has its name, where it is based and what it does. Put
it on the page, near the price.