Get $TOKEN per Authentication first. This needs jq (the same threading idiom the CLI uses).
Flights
# 0. A departure date ~60 days out, so this block never carries a past date
FROM_DATE=$(date -u -v+60d +%F 2>/dev/null || date -u -d '+60 days' +%F)
# 1. Create a search (IATA airport or city codes; results settle async)
SEARCH_ID=$(curl -s -X POST "https://api.wego.com/v1/flights/searches" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"from":"DXB","to":"LHR","fromDate":"'"$FROM_DATE"'","adults":1}' | jq -r .searchId)
# 2. Read ranked results and take a trip id (empty? rerun: results settle async)
TRIP_ID=$(sleep 3; curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/flights/searches/$SEARCH_ID/results" | jq -r '.results[0].tripId')
# 3. Open the trip (full itinerary, every fare) and take its Wego fare id
# (null? that trip has no Wego fare: try another tripId from step 2)
FARE_ID=$(curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/flights/trips/$TRIP_ID?searchId=$SEARCH_ID" \
| jq -r '[.fares[] | select(.kind=="wego")][0].fareId')
# 4. Pick a fare option (Saver, Flex and similar). The list is ordered by leg
# first, then by price within a leg - so options[0] is the cheapest option of
# leg 1, not the cheapest of the fare.
# REQUIRED: step 5 rejects a request with no fareOptionId (400 validation_failed).
# This route is one-way, so one id is the whole trip. Read the fare's own
# top-level `price` for the trip total; never add or min() the options.
FARE_OPTION_ID=$(curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/flights/fares/$FARE_ID/options" \
| jq -r '.options[0].fareOptionId')
# 5. Get the wego.com URL (the booking-link endpoint)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/flights/fares/$FARE_ID/booking-link?tripId=$TRIP_ID&fareOptionId=$FARE_OPTION_ID&from=DXB&to=LHR&fromDate=$FROM_DATE"
# -> { "bookingUrl": "https://www.wego.com/...", "expires": true }Adding a return date? Then step 4 has a case to check that a one-way does not.
Each option carries price.covers: "trip" means that one id prices the whole
journey and step 5 takes it alone, exactly as above; "leg" means it prices only its
own leg. Send a single "leg" id and the booking page still presents the round trip
while pricing half of it, with nothing in the response to say so. So when the options
report "leg", group them by legId, take one per entry in legs[], and pass them
to step 5 as a comma-separated fareOptionId (at most 8, none twice). covers is a
positive witness: absent means the API could not attribute the option, not that it
covers the trip. See Fares, rates and partners.
Do not know the code? GET /v1/places?query=dubai resolves free text to typed places
with codes – cities, airports, states, districts and hotels, so it is also where a
hotelId for the hotels funnel comes from. When the response sets
metadata.hasAmbiguity, ask the traveler which place they meant before searching.
Hotels
Nearly the same shape, with one extra step: a city search holds only a sample of any
one hotel’s rates, so pricing a hotel’s full room list takes a second search
created with that hotelId. Skip it and the rates read answers 409
rates_require_hotel_search.
CHECK_IN=$(date -u -v+60d +%F 2>/dev/null || date -u -d '+60 days' +%F)
CHECK_OUT=$(date -u -v+63d +%F 2>/dev/null || date -u -d '+63 days' +%F)
# 1. Create a city search
CITY_SEARCH=$(curl -s -X POST "https://api.wego.com/v1/hotels/searches" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"cityCode":"DXB","checkIn":"'"$CHECK_IN"'","checkOut":"'"$CHECK_OUT"'","adults":2}' | jq -r .searchId)
# 2. Read ranked results and take a hotelId
# (null? rerun: results settle async. Read the top-level searchComplete flag to
# know when to stop - see How search works)
HOTEL_ID=$(sleep 4; curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/hotels/searches/$CITY_SEARCH/results" | jq -r '.results[0].hotelId')
# 3. REQUIRED: a second search, scoped to that hotel
HOTEL_SEARCH=$(curl -s -X POST "https://api.wego.com/v1/hotels/searches" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"hotelId":"'"$HOTEL_ID"'","checkIn":"'"$CHECK_IN"'","checkOut":"'"$CHECK_OUT"'","adults":2}' | jq -r .searchId)
# 4. Rooms and rates, cheapest first (a rate's id is `id`, not `rateId`)
# (null? rerun: rates land over a few seconds too)
RATE_ID=$(sleep 4; curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/hotels/$HOTEL_ID/rates?searchId=$HOTEL_SEARCH" | jq -r '.rates[0].id')
# 5. Get the wego.com checkout URL
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.wego.com/v1/hotels/$HOTEL_ID/rates/$RATE_ID/booking-link?searchId=$HOTEL_SEARCH"
# -> { "bookingUrl": "https://www.wego.com/hotels/booking/checkout?...", "expires": true }For endpoint details and parameters, see the API Reference.