Google Flights data, with the price band attached.
Two endpoints over live Google Flights results. Every itinerary comes back with Google’s historical price range, its verdict on today’s fare, and a deep link that reopens exactly that itinerary.
POST https://api.flightpowers.com/v1/flights/oneway
x-api-key: <your RapidAPI key>
content-type: application/json
{
"from_airport": "JFK",
"to_airport": "LHR",
"departure_date": "2026-09-22",
"max_stops": 0,
"currency": "usd",
"limit": 5
}The flagship field
price_insights_low, price_insights_high, and a verdict.
Google Flights shows travellers a historical price range and tells them whether the current fare sits low, typical or high within it. Those three values come back on every result row.
{
"price_insights_low": 65,
"price_insights_high": 135,
"price_range_in_relation_to_other_periods": "low",
"price": "$56",
"price_as_number": 56
}price_insights_low and price_insights_high are integers in the currency you requested, taken from the price-history data on the Google Flights page the search loads.
price_range_in_relation_to_other_periods is Google’s own label for the current fare — "low", "typical" or "high".
Handle the null case
Google does not publish a band for every search. When it is absent these fields come back null. Do not make them required in your schema, and do not build a UI that has nothing to show without them.
POST /v1/flights/roundtrip
A round trip is one search, not two.
The endpoint runs a genuine paired-leg search: the outbound leg it selects drives a filtered query for the matching return. You get a combined price and a single buy_link for an itinerary that can be bought as one ticket.
POST https://api.flightpowers.com/v1/flights/roundtrip
{
"from_airport": "JFK",
"to_airport": "LHR",
"departure_date": "2026-09-22",
"return_date": "2026-09-29",
"max_departure_stops": 0,
"max_return_stops": 1,
"departure_airline_codes": ["BA"],
"return_departure_time_min": 10,
"limit": 5
}Each leg takes its own constraints, which is the part two stapled one-way searches cannot express:
max_departure_stops / max_return_stopsintStop limits set independently per leg — non-stop out, one stop back.
departure_airline_codes / return_airline_codesstring[]Restrict each leg to particular carriers. Matching exclude_ variants exist for both legs.
departure_departure_time_min / _maxintDeparture and arrival time windows, set separately for the outbound and return legs.
total_pricestringThe combined price for the paired itinerary, returned on the result.
POST /v1/flights/oneway
Request fields
Required
from_airportstringOrigin IATA code.
to_airportstringDestination IATA code.
departure_datestringYYYY-MM-DD.
Optional
max_stopsintMaximum stops per itinerary.
airline_codes / exclude_airline_codesstring[]Include or exclude specific carriers.
departure_time_min / _max, arrival_time_min / _maxintHour-of-day windows.
currencystringDefaults to usd.
max_priceintUpper bound on fare.
passengersint[]Passenger breakdown.
limitintNumber of itineraries returned. Defaults to 10.
strictboolWhen the search fails to complete, return 503 instead of an empty array. Available on the RapidAPI host.
Rate limits
Scanning a month of dates.
Cheapest-date and fare-alert products are date scans, and a date scan is bounded by requests per minute. Pro allows 150 per minute, Ultra 250, Mega 500 — as listed on RapidAPI on 2026-08-25.
# One month of departure dates, scanned in parallel.
# Each date is one request; keep concurrency under your plan's per-minute limit.
import asyncio, httpx, datetime as dt
KEY = os.environ["RAPIDAPI_KEY"] # server-side only
DATES = [dt.date(2026, 9, 1) + dt.timedelta(days=i) for i in range(30)]
async def fare(client, day):
r = await client.post(
"https://api.flightpowers.com/v1/flights/oneway",
headers={"x-api-key": KEY},
json={"from_airport": "JFK", "to_airport": "LHR",
"departure_date": day.isoformat(), "limit": 1},
timeout=180,
)
rows = r.json()
return day, (rows[0]["price_as_number"] if rows else None)
async def main():
limits = httpx.Limits(max_connections=20)
async with httpx.AsyncClient(limits=limits) as client:
return await asyncio.gather(*(fare(client, d) for d in DATES))Thirty dates is thirty billed requests. Keep your client’s connection limit under your plan’s per-minute figure; a 429 is returned to you unchanged and is never retried, so an exhausted quota is never double-billed.
Pricing
Plans on RapidAPI
| Plan | Per month | Requests | Rate limit | Beyond quota |
|---|---|---|---|---|
| Basic | $0 | 10 / month | — | hard stop |
| Pro | $10 | 2,500 / month | 150 / minute | $0.003 per extra request |
| Ultrarecommended | $25 | 10,000 / month | 250 / minute | $0.003 per extra request |
| Mega | $50 | 50,000 / month | 500 / minute | $0.001 per extra request |
Read from the live RapidAPI listing on 2026-08-25. RapidAPI bills; one call to any endpoint counts as one request. Check the listing for the current figures before you commit.
Flights API questions
- Which fields identify a good price?
- price_insights_low and price_insights_high are the ends of the historical price band Google Flights shows for that route and date, as integers in the requested currency. price_range_in_relation_to_other_periods is Google’s verdict on the current fare: "low", "typical" or "high". All three can be null when Google does not publish a band for a search, so treat them as optional in your schema.
- What is in buy_link?
- A Google Flights URL of the form https://www.google.com/travel/flights?tfs=<encoded>&curr=<currency>. The encoded payload carries the passengers, cabin, trip type and every leg’s date, airports, airline and flight number, so the link reopens that exact itinerary rather than a fresh search. Round-trip results carry one combined link for the paired itinerary.
- How do I scan many dates at once?
- Each date is a separate request, so a month scan is thirty calls. The per-minute rate limit on your plan is what bounds the concurrency: 150 per minute on Pro, 250 on Ultra, 500 on Mega, as listed on RapidAPI on 2026-08-25. Keep your client’s connection limit under that and a month of dates finishes in one batch.
- What do the response airports look like?
- Requests take IATA codes (from_airport, to_airport). Responses return them as a display string in the form "City (IATA)" — for example "New York (JFK)" — not as a bare code. Parse accordingly if you round-trip values through your own storage.
- Is price a string or a number?
- Both, in two fields. price is the formatted string, for example "$56". price_as_number is the integer. Use price_as_number for arithmetic. stops is an integer, but can be the string "Unknown" when the itinerary’s stop count could not be read, so guard for that.
- How long can a search take?
- The front allows up to 180 seconds for a search before it times out, because a live scrape of Google Flights is not a cache lookup. Set your client timeout accordingly — a default 30-second HTTP timeout will cut off searches that would have succeeded.