Round-Trip Flight API
A round trip is one search, not two
POST both dates and get paired itineraries, outbound and return already matched, with a combined price, duration, and one booking link.
total_price · total_duration_seconds · total_stopson every itinerary- Per-leg controls: stops, carriers, and time windows set separately for out and back
- "Empty" and "failed" stay distinguishable even across the return-leg fan-out, see search status
Free tier on RapidAPI. No card to try.
{
"from_airport": "BER",
"to_airport": "CDG",
"departure_date": "2026-10-06",
"return_date": "2026-10-13",
"limit": 5,
"currency": "usd"
}Short answer
What a round-trip search returns
POST /v1/flights/roundtrip on api.flightpowers.com (the same endpoint is /api/google_flights/roundtrip/v1 on google-flights-live-api.p.rapidapi.com with a RapidAPI key) takes a route plus departure_date and return_date, and returns one flat object per paired itinerary: outbound and return already matched, with a combined price, a combined duration, a combined stop count, one booking link, and Google's price band on the pair rather than on either leg.[
{
"from_airport": "Berlin (BER)",
"to_airport": "Paris (CDG)",
"departure_date": "2026-10-06",
"return_date": "2026-10-13",
"total_price": "$112",
"total_price_as_number": 112,
"total_duration_seconds": 12900,
"total_stops": 0,
"departure_flight_airline": "easy | Jet",
"departure_flight_duration": "1 hr 50 min",
"return_flight_airline": "easy | Jet",
"return_flight_duration": "1 hr 45 min",
"price_insights_low": 120,
"price_insights_high": 220,
"price_range_in_relation_to_other_periods": "low"
}
]| Field | Type | Meaning | Above |
|---|---|---|---|
total_price / total_price_as_number | string · number | The fare for the whole paired trip, as a display string and as a sortable number. Not the sum of two separately priced one-ways. | $112 · 112 |
total_duration_seconds | number | Flying time of both legs combined, in seconds. | 12900 |
total_stops | int | Stops across both legs together. 0 means nonstop in each direction. | 0 |
departure_flight_* / return_flight_* | fields | Each leg in full: _airline, _duration, _stops, plain-text departure and arrival descriptions, and departure_stops_info / return_stops_info per layover. | 1 hr 50 min out, 1 hr 45 min back |
buy_link | string | One Google Flights deep link for the whole paired itinerary, both legs, in the requested currency. | google.com/travel/flights?tfs=… |
price_range_in_relation_to_other_periods | "low" | "typical" | "high" | null | Google's verdict on the trip total against its price_insights_low / price_insights_high band for these dates. | low |
The return-leg fan-out happens inside the API, so a paired search bills as a single request however many outbound candidates it prices.
The band rides on the pair, which is what makes it useful here: one call answers whether the whole trip is cheap, instead of two one-ways you have to add up and then judge yourself. Same three fields as on price insights.
The same capture, rendered
A real week in Paris, $112, marked low
Berlin→Paris with both legs paired. The cheapest captured itinerary sits below Google's own band for the route, so it arrives wearing the verdict.
BER→CDG · 2026-10-06 → 2026-10-13
captured run · 2026-08-26Google's price band. Cheapest paired itinerary: $112
Each row is one object from the response. The low badge is price_range_in_relation_to_other_periods rendered directly, Google's own call that $112 is under the usual $120–$220 range for these dates.
Response shape
One object per itinerary
No leg-matching on your side: the pairing, the totals, and the single booking link are the endpoint's job.
total_price / total_price_as_numberstring · numberThe combined fare for the paired itinerary, $112 in the capture, as a display string and a sortable number. Not the sum of two separately-priced one-ways.
total_duration_secondsnumberBoth legs' flying time combined, in seconds.
total_stopsintStops across both legs: 0 means nonstop in each direction.
buy_linkstringOne Google Flights deep link for the whole paired itinerary, both legs, in the requested currency.
departure_flight_*fieldsThe outbound leg in full: departure_flight_airline, departure_flight_duration, departure_flight_stops, plain-text departure and arrival descriptions, and departure_stops_info per layover.
return_flight_*fieldsThe return leg, same structure, already matched to that exact outbound.
price_insights_low / high + verdictnumber · string | nullGoogle's band and low | typical | high verdict for the route and date pair, same as one-way. Null when Google doesn't publish a band.
Request
Every one-way control, twice
Four required fields; then each leg takes its own constraints, the part two stapled one-way searches cannot express.
Required
departure_date / return_datestringBoth travel dates, YYYY-MM-DD.
from_airport / to_airportstringIATA codes.
Optional · per leg
max_departure_stops / max_return_stopsintStop limits per leg: nonstop out, one stop back is one request.
departure_airline_codes / return_airline_codesstring[]Carrier restrictions per leg, with departure_exclude_airline_codes and return_exclude_airline_codes to remove carriers instead.
departure_departure_time_min / _maxint 0–23Outbound departure-hour window, with departure_arrival_time_min / _max for its arrival.
return_departure_time_min / _maxint 0–23The same pair of windows for the return leg.
There is no max_stops field here: on the RapidAPI endpoints use max_departure_stops / max_return_stops. (Calling through api.flightpowers.com instead, max_stops is accepted there as a convenience alias for both.)
Optional · shared
sort_type · currency · max_price · seat_type · passengers · limit · strict · use_ext_proxyExactly as on one-way, applied to the paired search as a whole.
The honest comparison
Paired search vs. two one-ways, stapled
Stapling two one-way calls together is the workaround most flight APIs leave you with. Here is what it actually costs.
Two one-way calls
- Two requests billed per date pair, so a flexible-date round-trip scan costs double.
- No combined total: you add two fares that may not be purchasable as one ticket at that price.
- Leg combinations are yours to cross-match, filter, and de-duplicate.
- Two separate booking links that never open a single round-trip purchase.
POST /roundtrip
- One request, one billed search, however many outbound candidates it prices.
total_priceis the itinerary priced as one purchase.- Legs arrive pre-paired, with per-leg filters applied inside the search.
- One
buy_linkthat reopens the exact paired itinerary.
The hard part, handled
Honest empty-vs-failed reporting is harder on round-trips than it sounds: a round-trip prices a return leg for every outbound candidate, and each of those fetches can fail on its own. empty is only reported when every candidate was attempted and every one read a real Google Flights page saying it had nothing. A fan-out that was blocked, or that stopped on the request's time ceiling, reports degraded or partial, never "no flights". The search-status page documents the full contract.
Pricing
Round-trip search on every plan
| Plan | Price / mo | Requests | $ / 1k req | Overage | Rate limit | |
|---|---|---|---|---|---|---|
| BASIC | Free | 10 / mo | — | hard cap | — | Get this plan → |
| PRO | $10 | 2,500 / mo | $4.00 | $0.003 / req | 150 / min | Get this plan → |
| ULTRArecommended | $25 | 10,000 / mo | $2.50 | $0.003 / req | 250 / min | Get this plan → |
| MEGA | $50 | 50,000 / mo | $1.00 | $0.001 / req | 500 / min | Get this plan → |
Swipe the table sideways for overage and rate limits.
Every plan on this API includes all of its endpoints; flights and hotels are separate subscriptions. Read from the live listing on 2026-09-11; the listing is authoritative.
Questions, answered plainly
- Does the API return round-trip prices as one itinerary?
- Yes. POST /roundtrip returns one flat JSON object per itinerary with total_price, total_price_as_number, total_duration_seconds, total_stops, and both legs’ details already paired under departure_flight_* and return_flight_* fields.
- Can I set different filters for the outbound and return legs?
- Yes. Every one-way filter exists per leg: max_departure_stops and max_return_stops, departure_airline_codes and return_airline_codes (with exclude variants), and separate departure/arrival time windows for each leg. Nonstop out, one stop back with a morning return is a single request.
- Why not two one-way calls?
- Two one-way searches cost two requests per date pair, give you no combined total, and price legs independently. The sum of two one-way fares is not the fare of a round-trip ticket. The paired endpoint prices the itinerary as one purchase and ships one buy_link for it.
- Is buy_link for the whole round trip?
- Yes. One combined Google Flights deep link that reopens the exact paired itinerary, both legs, ready to book as one ticket.
- What does an empty round-trip response mean?
- Check X-Search-Status before deciding. A round-trip prices a return leg for every outbound candidate, and each of those fetches can fail on its own, so "empty" is only reported when every candidate read a real Google Flights page saying it had nothing. A blocked or truncated fan-out reports "degraded" or "partial", never "no flights".
- Do the price-insights fields work on round-trips?
- Yes. Each itinerary carries price_insights_low, price_insights_high, and the low | typical | high verdict for the route and date pair. The captured $112 BER→CDG itinerary on this page came back marked "low" against a $120–$220 band.
- How many requests does a round-trip search cost?
- One. The return-leg fan-out happens inside the API: a whole paired search, however many outbound candidates it prices, bills as a single request.
Stop stapling one-ways together
Paired itineraries with combined totals, per-leg filters, and one booking link, in a single request.
Free tier: 10 requests/month. No card to try.