Flight Price History & Booking Timing
Pricing
from $8.00 / 1,000 route price profile collecteds
Flight Price History & Booking Timing
Is this a good price? For any route: today's cheapest fare against that route's usual price, a low/typical/high verdict, 61 days of daily price history on the very first run, and how far ahead the route is normally cheapest to book — by week, month and weekday.
Answers the two questions every traveller and every fare-content page asks: is this a good price, and when should I book? Give it a list of routes and a departure date, and each route comes back with today's cheapest fare set against that route's own usual price, a plain verdict — low, typical or high — the last 61 days of daily prices behind that verdict, and how far ahead the route is normally cheapest to book, week by week, month by month and day by day. The price history arrives with the very first run: there is no waiting weeks for your own history to build up. No account and no login are needed — just run it.
What you can do with it
- Publish "should I book now?" content — a verdict, a usual price and a 61-day price line for every route on your site, refreshed on a schedule.
- Build a when-to-book guide — the cheapest week to book ahead, the cheapest month to fly and the cheapest day of the week, per route, with the exact averages behind each one.
- Sanity-check a fare you found — see instantly whether today's cheapest is above or below what that route usually costs, and where it sits against the lowest and highest price in the 61-day history collected for that same row.
- Score a route list — run hundreds of routes and sort by how far today's price sits from typical to find the ones worth writing about.
- Brief a travel-planning or chat product — hand it the usual price, the history and the booking window instead of a single fare with no context.
- Compare markets honestly — the same route priced the way travellers in the United States, the United Kingdom, Germany or India see it, each row labelled with the currency it actually came back in. The when-to-book half is published for five markets (US, GB, DE, FR, ES) and every row names the market its when-to-book figures describe.
What you get
One row per route. Real, abridged example:
{"routeId": "JFK-LAX-2026-09-30","route": "JFK-LAX","origin": "JFK","destination": "LAX","departureDate": "2026-09-30","tripType": "one_way","cabinClass": "economy","market": "US","source": "google-flights","collectedAt": "2026-08-16T18:00:00.000Z","currency": "USD","currencyFromSource": true,"priceVerdict": "typical","currentCheapestPrice": 169,"typicalPrice": 156,"deltaVsTypical": 13,"typicalPriceRangeLow": 100,"typicalPriceRangeHigh": 185,"hasPriceHistory": true,"priceHistoryPoints": 61,"priceHistoryStartDate": "2026-06-17","priceHistoryEndDate": "2026-08-16","priceHistoryTimezone": "America/New_York","priceHistoryLowPrice": 126,"priceHistoryHighPrice": 178,"priceHistory": [{ "date": "2026-06-17", "epochMs": 1781668800000, "price": 154 },{ "date": "2026-06-18", "epochMs": 1781755200000, "price": 154 }],"bookByWindow": "now, until Sep 16","bookByDate": "Sep 16","flightsFoundOnDate": 32,"cheapestFlightPriceOnDate": 169,"airlinesOnRoute": [{ "code": "AA", "name": "American" },{ "code": "B6", "name": "JetBlue" },{ "code": "DL", "name": "Delta" }],"airlineCount": 13,"connectingHubs": [{ "code": "ORD", "city": "Chicago" },{ "code": "DFW", "city": "Dallas" }],"routePriceLow": 169,"routePriceHigh": 992,"shortestDurationMin": 350,"longestDurationMin": 1484,"bookingTimingStatus": "ok","bookingTimingSource": "kayak","bookingTimingMarket": "US","bookingTimingMarketIsRequestedMarket": true,"bookingTimingCurrency": "USD","bestBookingWindowWeeks": 3,"bestBookingWindowSavingsPercent": 36,"cheapestObservedWeeksBefore": 12,"cheapestObservedWeeksBeforePrice": 331,"priceByWeeksBeforeDeparture": [{ "weeksBefore": 26, "label": "26", "price": 428 },{ "weeksBefore": 12, "label": "12", "price": 331 },{ "weeksBefore": 1, "label": "1", "price": 605 }],"priceByWeeksBeforeDepartureBasis": "To calculate weekly average prices, KAYAK takes all prices for each week before departure over the last year for round-trip flights from New York to Los Angeles…","monthlySeasonality": [{ "monthNumber": 1, "month": "January", "label": "Jan", "price": 294 },{ "monthNumber": 6, "month": "June", "label": "Jun", "price": 490 }],"cheapestMonth": "January","mostExpensiveMonth": "June","priceByWeekday": [{ "weekdayNumber": 4, "weekday": "Thursday", "label": "Thu", "price": 427.4 },{ "weekdayNumber": 7, "weekday": "Sunday", "label": "Sun", "price": 555.4 }],"cheapestWeekday": "Thursday","mostExpensiveWeekday": "Sunday","cabinClassPrices": [{ "cabinClass": "economy", "label": "Economy", "price": 739.17 },{ "cabinClass": "business", "label": "Business", "price": 3774.99 }],"recentCheapestPrice": 310,"averageFlightDuration": "5h 59m","averageFlightDurationMin": 359}
Alongside the table, every run writes a summary that counts, separately, the rows produced, the routes read, the routes the sources publish nothing for, the routes that could not be read at all, the routes rejected before the run started and the when-to-book profiles added. A route that could not be read is never counted as a route with no data.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
routes | list of text | JFK-LAX, LHR-DXB | One route per line as two three-letter codes. Airport codes (JFK, LHR) or city codes covering every airport in a city (NYC, LON). One row comes back per route. |
departureDate | text | +30 | The day to price. An exact day (2026-09-15) or a number of days from the day the run starts (+30). Up to 330 days ahead. |
tripLengthDays | integer | empty | Empty prices a one-way trip. A number of nights prices a return trip departing on your date and coming back that many nights later. Maximum 60. |
cabinClass | select | economy | Economy, premium economy, business or first. The verdict, the usual price and the history are all specific to the cabin chosen. |
currency | select | USD | The currency to price in. Every row also states the currency that actually came back. |
market | select | US | The country you sell into. Fares and availability differ by market. The when-to-book half covers US, GB, DE, FR and ES; choose any other market and those figures come from the US market, and the row says so in bookingTimingMarket. |
includeBookingTiming | boolean | true | Adds the when-to-book figures: price by week before departure, cheapest month, cheapest weekday and average price by cabin. Published for five markets — US, GB, DE, FR and ES — with every other market answered by the US one and labelled as such on the row. |
includeRouteMetadata | boolean | true | Adds the airlines on the route with their names, the connecting airports, and the route's price and journey-time ranges. |
maxRoutes | integer | 50 | Safety cap on how many routes one run covers. Maximum 200. |
parallelRoutes | integer | 4 | How many routes to work on at once. Maximum 6. |
Output fields
| Field | What it is |
|---|---|
routeId, route, origin, destination | The route this row is about. |
departureDate, returnDate, tripType, cabinClass, market | What was priced. |
currency, currencyFromSource | The currency the fare figures came back in, and whether it was stated by the source rather than assumed. |
priceVerdict | The published verdict for this route today: low, typical or high. Null when none is published. |
currentCheapestPrice | Today's cheapest fare for this route and date. |
typicalPrice | What this route usually costs. |
deltaVsTypical | Today's cheapest minus the usual price. Positive means it is above usual. |
typicalPriceRangeLow, typicalPriceRangeHigh | The source's own usual-price band for this route — the range it brackets typicalPrice with. It is not an all-time low and high: on most routes the route's own daily history below runs outside this band, which is normal and is what the band means. |
hasPriceHistory, priceHistoryPoints | Whether a price history is published for this route, and how many days of it. |
priceHistoryStartDate, priceHistoryEndDate | The span the history covers. |
priceHistoryLowPrice, priceHistoryHighPrice | The lowest and highest price in that history — the extremes actually observed over the span above, and the only ones this actor claims. |
priceHistoryTimezone | The zone every history date is stated in: the origin's own. Each day in the series is a day as it was lived at the origin, so a route out of Auckland is dated on Auckland's calendar and one out of New York on New York's. |
priceHistory | The daily series: date, epochMs and price per day. |
bookByWindow, bookByDate | The published "book by" advice, when there is one. Often there is not. |
flightsFoundOnDate, cheapestFlightPriceOnDate | How many flights were published for that exact date, and the cheapest of them. |
airlinesOnRoute, airlineCount | Which airlines fly the route, with their names. |
connectingHubs | The airports flights on this route connect through, with city names. |
routePriceLow, routePriceHigh | The route's published price range. |
shortestDurationMin, longestDurationMin | The route's journey-time range in minutes. |
bookingTimingStatus | ok, not_published, empty, failed, skipped or not_requested — what happened to the when-to-book look-up. |
bookingTimingSource, bookingTimingCurrency | Where the when-to-book figures came from and the currency they are in — which can differ from the fare currency. |
bookingTimingMarket, bookingTimingMarketIsRequestedMarket | The market whose travellers the when-to-book figures describe, and whether that is the market you asked for. When-to-book figures exist for five markets — US, GB, DE, FR and ES — so a row asked for in any other market carries US figures here and says so. |
bestBookingWindowWeeks, bestBookingWindowSavingsPercent | How many weeks ahead this route is normally best booked, and the saving that implies. |
cheapestObservedWeeksBefore, cheapestObservedWeeksBeforePrice | The cheapest week-before-departure in the published curve, and its average price. |
priceByWeeksBeforeDeparture | The full curve: average price for each of the 26 weeks before departure. |
monthlySeasonality, cheapestMonth, mostExpensiveMonth | Average price by month of the year, and the extremes. |
priceByWeekday, cheapestWeekday, mostExpensiveWeekday | Average price by day of the week, and the extremes. |
cabinClassPrices | Average price per cabin on this route. |
recentCheapestPrice | The lowest fare the when-to-book source has seen on this route recently. |
averageFlightDuration, averageFlightDurationMin | The route's average journey time, as text and in minutes. |
...Basis fields | For every averaged series, the source's own description of what it measured and over what period. Read it before comparing two series — they do not all cover the same window or the same trip type. |
collectedAt | When the row was collected. |
Pricing
You pay per result, not per minute.
- Route price profile collected — $8.00 per 1,000 rows. One row is a whole analytics record: the verdict, the usual price, the usual-price band, up to 61 days of daily prices with their own low and high, and the route's airlines and connecting airports.
- When-to-book figures added — $0.015 each. Charged only when the figures actually exist for that route and are attached to the row. A route with no when-to-book data published costs you nothing extra, and neither does a run with the option switched off.
Worked example. 50 routes with when-to-book figures switched on, and figures found for 45 of them: 50 rows at $8.00 per 1,000 is $0.10, plus 45 × $0.015 = $0.68. Total $0.78 for 50 complete route profiles carrying roughly 3,000 dated prices between them.
Limits & what this actor cannot do
- Fares are a snapshot. The cheapest price is what was published at the moment of collection. Airline pricing changes continuously and a fare seen now may be gone later.
- It reports, it does not book. It cannot hold a seat, buy a ticket or guarantee that a fare is still available.
- The price history is published, not accumulated here. It is the source's
own daily series of roughly the last two months. It cannot be extended
backwards, and it is not always published: some perfectly ordinary routes
come back with flights and prices but no history at all. Those rows say so
(
hasPriceHistory: false) rather than showing an invented line. - The "book by" advice is often missing. On most routes tested nothing is published, and the field is then null. Null means "not published" — never "book any time".
- The when-to-book figures are averages, each over its own period. They are computed by their source from what travellers there searched for, over different periods per series, and some cover return trips while others cover one-way. Every series carries its own description; do not compare two series without reading them.
- Two halves, two currencies. The fare figures and the when-to-book figures are priced by their own sources and can arrive in different currencies. Both are labelled and nothing is ever converted between them, because a converted figure would look precise and be wrong.
- The when-to-book half covers five markets: US, GB, DE, FR and ES. Pick any
other market and the fare half of the row is collected for the market you
chose, while the when-to-book half is answered by the US market — a different
travelling public, so the cheapest weekday and the cheapest month themselves
change, not only the currency. That is never left to be inferred: the row
carries
bookingTimingMarketandbookingTimingMarketIsRequestedMarket, and the run says it in its warnings and its summary. Switch the option off if only your own market's figures will do. - The usual-price band is not an all-time range.
typicalPriceRangeLowandtypicalPriceRangeHighare the source's own band of usual prices for the route — the range aroundtypicalPrice. Days outside it are ordinary and common, on most routes many of them. For a true low and high, usepriceHistoryLowPriceandpriceHistoryHighPrice, which are measured from the dated series in the same row and cover exactly the span that row states. - History days are the origin's days. Every date in the price history is the
day as it was at the origin, and
priceHistoryTimezonenames that zone. Joining two routes from different parts of the world ondatecompares their own local days, which is what a daily fare series means — not a single worldwide clock. - Results differ by market. A market is a separate inventory, not a currency swap. Rows from different markets should not be compared as if they were the same numbers.
- Nothing is invented. A missing price, month, week or verdict is null. No interpolation, no carrying a price from one day to the next, no filling gaps.
- Dates are limited to 330 days ahead, and a past date is refused before the run starts rather than coming back as an empty answer.
- Routes are seasonal. A route with nothing published on your date is reported as having nothing — that is an answer, not an error.
- A route with no published prices at all produces no row. Small regional routes sometimes publish flights but no price of any kind. Those routes are named in the run summary as having nothing published, the when-to-book look-up is skipped for them, and you are not charged for them — rather than handing you a row whose price columns are all empty.
- A refused read is reported as a failed read, never as "no data for this route". If every route in a run is refused, the run itself fails rather than finishing green with an empty table.
- Speed depends on the size of the job and on how quickly the sources answer. No fixed throughput is promised.
- The sources' terms govern automated access. You are responsible for using the data lawfully and in line with those terms.
FAQ
Do I need an account on Google Flights or Kayak? No. Nothing is signed into and no account of yours is used.
Does it need my login or password? No. There is no credential of any kind in the setup.
Can I schedule it? Yes. A daily or weekly schedule is the normal way to use it — each run appends a fresh, dated snapshot of every route's verdict and history, which is exactly what a fare-trend page or a "should I book?" widget needs.
Are the fares bookable? They are what the source published at the moment of collection. Treat them as a reference price, not a reservation: pricing moves continuously and the actor cannot hold or buy anything.
Why does one of my routes have no price history?
Because none is published for it. It happens on perfectly ordinary routes — the
row still carries the flights found, the route's airlines and, where it exists,
the when-to-book curve, and hasPriceHistory tells you plainly which rows have
a series and which do not.
Why are the when-to-book numbers in a different currency from the fares?
Because they come from a different source with its own point of sale. Each half
of the row states its own currency and nothing is converted, so the numbers stay
exactly as published. If that currency is not the one you expected, check
bookingTimingMarket: it names the market those figures describe, which for any
market outside US, GB, DE, FR and ES is the US one.
I chose India (or Japan, Canada, Australia…) — whose when-to-book figures do I
get?
The US market's, because when-to-book figures are published for five markets
only. Every row says so in bookingTimingMarket, the run warns about it before
collecting anything, and the fare half of the row is still the market you chose.
These are not the same numbers rescaled — a different set of travellers searched
them — so treat the cheapest weekday and cheapest month as US figures, or turn
the option off.
What happens if a route cannot be read at all? It is counted as a failed read in the run summary, with the route and the reason listed. It is never mixed in with the routes that genuinely have nothing.