Search flights by route and date
Search priced flight itineraries for a route and a date. `origin`, `destination` and `departureDate` are the only required fields — two three-letter airport codes and a YYYY-MM-DD date — and every itinerary comes back with its price, its carriers, its segments with full airport names and times, its stop count and its layovers. `price` is `{amount, currency, formatted}` — a number, a currency code and a display string — and `priceType` says what the number covers: `"one_way"` or `"round_trip_total"`. Pass `currency` to price results in a specific one. Every itinerary measured was priced: 48 of 48 on JFK→LHR, 18 of 18 on DUB→STN, 18 of 18 on a LAX→NRT round trip, 44 of 44 on a nonstop business-class JFK→LHR search. **A round trip prices the whole trip but does not itemize the return.** Pass `returnDate` and `priceType` comes back `"round_trip_total"` — the amount covers both directions — while **`inbound` is `null`**. Each outbound option is priced against its cheapest matching return, and that return flight is not described. The total is real; the return leg's times are not in the response. Measured on a LAX→NRT round trip for two adults: 18 itineraries, every one priced, every `inbound` null. For a one-way search, omit `returnDate` — there is no implicit return window. **Read `stops`, not `segments.length`.** A one-stop itinerary can still carry a single `segments[]` entry — measured on a JFK→LHR option that came back with one segment, `stops: 1` and a 120-minute layover in Dublin. `stops` is the authoritative count and `layovers[]` carries the detail as `{airportCode, airportName, city, durationMinutes}`. Deriving the stop count from the segment list will report that itinerary as nonstop. **No matches is a 200, not an error.** A route and filter combination with nothing available returns `itineraries: []`, `itineraryCount: 0` and a note saying so in words — "No itineraries were found for these dates and filters." There is nothing to retry and nothing to mistake for a failure. Measured on a short-haul route with `nonstopOnly` and `cabinClass: "first"`. Every response carries `scrapedAt`, an ISO timestamp for when the fares were read. Fares move constantly, so use the response's own timestamp rather than the time you happened to look at it — that is what tells a caller how old the number in front of them is. Coverage spans full-service and low-cost carriers alike, and you can see it in the results rather than take it on trust: one measured DUB→STN search returned Ryanair, Ryanair UK and Turkish Airlines side by side, with fares from $22, and a JFK→LHR search returned 48 priced itineraries in a single call. Filters narrow the search rather than the response: `cabinClass`, `nonstopOnly`, `adults`/`children`/`infants` and `currency` are all applied before the fares are read, and every one of them is echoed back on the response so a result set is self-describing. Billing: 1 credit per request, reported as `pagesFetched`. There is no paging. Measured on 17 September 2026, three runs each: JFK→LHR answered in 1.34-2.84s with 48 itineraries, DUB→STN in 1.67-1.86s with 18, a LAX→NRT round trip for two adults in 1.68-2.76s with 18, and a nonstop business-class JFK→LHR search in 1.78s with 44.
/search Search https://api.fetchlayer.dev/flights/search Headers
Authorization string required Bearer token — your FetchLayer API key.
Parameters
origin string required Departure airport as its three-letter code, e.g. "JFK". Anything else is a 400 naming it: `{"error":"origin: must be a 3-letter airport code"}`.
destination string required Arrival airport as its three-letter code, e.g. "LHR". Same rule as `origin`.
departureDate string required Departure date, YYYY-MM-DD. **Must not be in the past** — a past date is a 400 that names it, `{"error":"departureDate \"2020-01-01\" is in the past"}`, so a hardcoded date in a scheduled job will start failing rather than silently returning nothing.
returnDate string optional Return date, YYYY-MM-DD. Omit for a one-way search — there is no implicit return window. Given, `tripType` becomes `"round_trip"`, the price covers both directions as `"round_trip_total"`, and `inbound` comes back null.
adults integer optional Adult travelers, 1 to 9. Prices are for the whole party, not per person. (default: 1)
children integer optional Children traveling, up to 9. (default: 0)
infants integer optional Infants traveling, up to 9. (default: 0)
cabinClass string optional Cabin to search: economy, premium_economy, business, first. (default: economy)
nonstopOnly boolean optional Only include itineraries with no stops. Combined with a narrow cabin on a short route this can legitimately return nothing — still a 200, with a note. (default: false)
currency string optional Currency to price results in, as its three-letter code, e.g. "USD". Echoed back on the response, and on every `price.currency`.
format string optional Envelope format: json or markdown. (default: json)
Response Fields
search
Search flights by route and date
transport string The route family. "flight-search".
notes string[] Caveats and completeness statements you can act on, in plain words. Empty on a search that found itineraries; on one that found none it carries "No itineraries were found for these dates and filters." — which is why an empty result never has to be guessed at.
pagesFetched number What the request is billed at: 1 credit. There is no paging on this route, so a search is always a single unit of work.
origin string The departure airport code, echoed back.
destination string The arrival airport code, echoed back.
departureDate string The outbound date the fares are for.
returnDate string The return date when you gave one, null on a one-way search.
tripType string `"one_way"` or `"round_trip"` — decided by whether you passed `returnDate`, and stated here so a result set does not depend on remembering the request.
adults number The adult count the prices cover.
children number As `adults`.
infants number As `adults`.
cabinClass string The cabin searched, echoed back.
nonstopOnly boolean Whether the search was restricted to nonstop itineraries.
currency string The currency the prices are in.
locale string The locale the times and names were read in, e.g. "en".
scrapedAt string **An ISO timestamp for when these fares were read.** Fares move; this is what tells you how old the number in front of you is, rather than when you got round to looking at the response.
itineraryCount number How many itineraries came back. 0 is an ordinary answer with a note, not a failure.
itineraries[].id string A short id for the itinerary within this response.
itineraries[].price object `{amount, currency, formatted}` — a number, a code and the display string, so no parsing is needed either way.
itineraries[].priceType string **What the price covers**: `"one_way"`, or `"round_trip_total"` on a search with `returnDate`, where the amount is for both directions.
itineraries[].airlines string[] Every carrier across the itinerary, e.g. `["British Airways"]` or `["Ryanair UK"]`.
itineraries[].outbound object The outbound leg: `{segments, stops, layovers, durationMinutes, airlines}`.
itineraries[].outbound.segments object[] Each flight in the outbound leg, in order: `{airline, departureAirportCode, departureAirportName, arrivalAirportCode, arrivalAirportName, departureTime, arrivalTime, departureDate, arrivalDate}`. Airports come with both the code and the full name, so "LHR" never has to be looked up. `departureDate` and `arrivalDate` are separate fields precisely because they differ on an overnight — a 4:55 PM departure landing at 8:05 AM the next day carries both dates.
itineraries[].outbound.stops number **The stop count for the outbound leg, and the field to read.** Not `segments.length - 1`: a one-stop itinerary can carry a single segment entry.
itineraries[].outbound.layovers object[] `[{airportCode, airportName, city, durationMinutes}]` — where the connection is and how long it lasts, so a two-hour Dublin layover and a five-hour one are distinguishable before anyone books either.
itineraries[].outbound.durationMinutes number Total elapsed time for the outbound leg in minutes, layovers included. A number, not "10 hr 10 min".
itineraries[].outbound.airlines string[] The carriers operating the outbound leg.
itineraries[].inbound string **Null on every search measured, including round trips.** On a one-way search there is no return leg to describe; on a round trip the price covers both directions but the return flight is not itemized. Treat the return leg as unavailable rather than as a field that failed to populate.
Request
curl -X POST "https://api.fetchlayer.dev/flights/search" \
-H "Authorization: Bearer ss-your-key" \
-H "Content-Type: application/json" \
-d '{"origin":"JFK","destination":"LHR","departureDate":"2026-10-15"}'Response
{
"transport": "flight-search",
"notes": [],
"pagesFetched": 1,
"origin": "JFK",
"destination": "LHR",
"departureDate": "2026-10-15",
"returnDate": null,
"tripType": "one_way",
"adults": 1,
"children": 0,
"infants": 0,
"cabinClass": "economy",
"nonstopOnly": false,
"currency": "USD",
"locale": "en",
"scrapedAt": "2026-09-17T11:59:41.161Z",
"itineraryCount": 48,
"itineraries": [
{
"id": "ul84o9",
"outbound": {
"segments": [
{
"airline": "British Airways",
"departureAirportCode": "JFK",
"departureAirportName": "John F. Kennedy International Airport",
"arrivalAirportCode": "LHR",
"arrivalAirportName": "Heathrow Airport",
"departureTime": "7:50 AM",
"arrivalTime": "7:45 PM",
"departureDate": "2026-10-15",
"arrivalDate": "2026-10-15"
}
],
"stops": 0,
"layovers": [],
"durationMinutes": 415,
"airlines": [
"British Airways"
]
},
"inbound": null,
"price": {
"amount": 295,
"currency": "USD",
"formatted": "295"
},
"priceType": "one_way",
"airlines": [
"British Airways"
]
},
{
"id": "zmpos7",
"outbound": {
"segments": [
{
"airline": "Aer Lingus",
"departureAirportCode": "JFK",
"departureAirportName": "John F. Kennedy International Airport",
"arrivalAirportCode": "LHR",
"arrivalAirportName": "Heathrow Airport",
"departureTime": "4:55 PM",
"arrivalTime": "8:05 AM",
"departureDate": "2026-10-15",
"arrivalDate": "2026-10-16"
}
],
"stops": 1,
"layovers": [
{
"airportCode": "DUB",
"airportName": "Dublin Airport",
"city": "Dublin",
"durationMinutes": 120
}
],
"durationMinutes": 610,
"airlines": [
"Aer Lingus"
]
},
"inbound": null,
"price": {
"amount": 295,
"currency": "USD",
"formatted": "295"
},
"priceType": "one_way",
"airlines": [
"Aer Lingus"
]
}
]
}