Skip to content

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_stops on 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.

POST /api/google_flights/roundtrip/v1
captured run · 2026-08-26
{
  "from_airport": "BER",
  "to_airport": "CDG",
  "departure_date": "2026-10-06",
  "return_date": "2026-10-13",
  "limit": 5,
  "currency": "usd"
}
Replays the captured request: free, no account, nobody's quota.

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.
BER → CDG, 2026-10-06 → 2026-10-13 · 1 of 5 itineraries, trimmed · captured 2026-08-26
[
  {
    "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"
  }
]
FieldTypeMeaningAbove
total_price / total_price_as_numberstring · numberThe 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_secondsnumberFlying time of both legs combined, in seconds.12900
total_stopsintStops across both legs together. 0 means nonstop in each direction.0
departure_flight_* / return_flight_*fieldsEach 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_linkstringOne 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" | nullGoogle'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-062026-10-13

captured run · 2026-08-26

Google's price band. Cheapest paired itinerary: $112

$120 low$220 high
$112lownonstop both waysbuy_link →
OUTeasy | Jet · 1 hr 50 min · 5:05 PM on Tue, Oct 6RETeasy | Jet · 1 hr 45 min · 8:50 AM on Tue, Oct 13
$113lownonstop both waysbuy_link →
OUTeasy | Jet · 1 hr 50 min · 6:15 AM on Tue, Oct 6RETeasy | Jet · 1 hr 45 min · 8:50 AM on Tue, Oct 13
$116lownonstop both waysbuy_link →
OUTAir France · 1 hr 50 min · 6:25 PM on Tue, Oct 6RETAir France · 1 hr 45 min · 7:10 AM on Tue, Oct 13
$116lownonstop both waysbuy_link →
OUTAir France · 1 hr 50 min · 7:55 PM on Tue, Oct 6RETAir France · 1 hr 45 min · 7:10 AM on Tue, Oct 13
$124lownonstop both waysbuy_link →
OUTAir France · 1 hr 50 min · 3:10 PM on Tue, Oct 6RETAir France · 1 hr 45 min · 7:10 AM on Tue, Oct 13

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 · number

The 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_secondsnumber

Both legs' flying time combined, in seconds.

total_stopsint

Stops across both legs: 0 means nonstop in each direction.

buy_linkstring

One Google Flights deep link for the whole paired itinerary, both legs, in the requested currency.

departure_flight_*fields

The 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_*fields

The return leg, same structure, already matched to that exact outbound.

price_insights_low / high + verdictnumber · string | null

Google'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_datestring

Both travel dates, YYYY-MM-DD.

from_airport / to_airportstring

IATA codes.

Optional · per leg

max_departure_stops / max_return_stopsint

Stop 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–23

Outbound departure-hour window, with departure_arrival_time_min / _max for its arrival.

return_departure_time_min / _maxint 0–23

The 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_proxy

Exactly 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_price is the itinerary priced as one purchase.
  • Legs arrive pre-paired, with per-leg filters applied inside the search.
  • One buy_link that 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

PlanPrice / moRequests$ / 1k reqOverageRate limit
BASICFree10 / mohard capGet this plan →
PRO$102,500 / mo$4.00$0.003 / req150 / minGet this plan →
ULTRArecommended$2510,000 / mo$2.50$0.003 / req250 / minGet this plan →
MEGA$5050,000 / mo$1.00$0.001 / req500 / minGet 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.