Getting Started
Priced flight itineraries as structured JSON. One route, three required fields, one credit per request.
1. Get your API key
Create an account and generate a FetchLayer API key from your dashboard. The same key works on every platform.
Create free account →2. Search a route
Two three-letter airport codes and a departure date. That is the whole 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"}'That returned 200 in 1.34–2.84s across three runs on 17 September 2026 with 48 itineraries, every one priced. Each looks like this:
{
"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"]
}A past departureDate is a 400, not an empty result
{"error":"departureDate \"2020-01-01\" is in the past"}. That is the behaviour you want in anything scheduled — compute the date rather than pinning it, or the job fails loudly the day it goes stale instead of quietly returning nothing. A malformed code is a 400 too: {"error":"origin: must be a 3-letter airport code"}. Low-cost carriers are in the results, not in a promise
3. Read the stop count from stops
This is the one thing on this API that will quietly give you wrong answers. A one-stop itinerary can carry a single segments[] entry — here is a real JFK→LHR result from the same sweep:
{
"segments": [ { "airline": "Aer Lingus", "departureAirportCode": "JFK", "arrivalAirportCode": "LHR", "departureDate": "2026-10-15", "arrivalDate": "2026-10-16" } ],
"stops": 1,
"layovers": [
{ "airportCode": "DUB", "airportName": "Dublin Airport", "city": "Dublin", "durationMinutes": 120 }
],
"durationMinutes": 610
}segments.length - 1 would call that a nonstop
stops is the authoritative count and layovers[] carries where the connection is and how long it lasts. Deriving stops from the segment list sells a one-stop itinerary as a direct flight. Durations are numbers and dates are separate fields
durationMinutes is minutes, layovers included, so sorting by journey length is arithmetic rather than parsing “10 hr 10 min”. Each segment carries departureDate and arrivalDate separately, which is how a 4:55 PM departure landing at 8:05 AM is unambiguously an overnight — and both airport codes come with their full names, so “LHR” never needs looking up. 4. Add a return date — and know what the price covers
curl -X POST https://api.fetchlayer.dev/flights/search \
-H "Authorization: Bearer ss-your-key" \
-H "Content-Type: application/json" \
-d '{"origin":"LAX","destination":"NRT","departureDate":"2026-10-15","returnDate":"2026-10-25","adults":2}'18 itineraries in 1.68–2.76s, all priced, tripType: "round_trip".
The price covers both directions; the return leg is not itemized
priceType comes back "round_trip_total" and inbound comes back null. Each outbound option is priced against its cheapest matching return, and that return flight is not described. The total is real and comparable; the return itinerary is not there to display. Stated up front, because an absent inbound otherwise reads as missing data. Omit returnDate for one-way
returnDate means tripType: "one_way" and priceType: "one_way" — the amount buys the flight described in outbound, and nothing else. 5. Narrow it
Filters are applied before the fares are read, and echoed back on the response so a stored result never depends on remembering the 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","cabinClass":"business","nonstopOnly":true,"currency":"USD"}'44 itineraries in 1.78s, all priced. cabinClass takes economy, premium_economy, business or first; adults runs 1–9 with children and infants alongside, and prices cover the whole party rather than one seat.
No matches is a 200, not an error
itineraries: [], itineraryCount: 0, and a note reading “No itineraries were found for these dates and filters.” Nothing to retry — an empty list is an answer about the market, not about the service. Check scrapedAt before trusting a price
scrapedAt, an ISO timestamp for when the fares were read. Fares move constantly, so that field — not the time you looked at the response — is what tells you how old the number is. Speed and billing
One credit per request, reported on every response as pagesFetched. There is no paging, so a search is always a single unit of work whether it returns 48 itineraries or none. Measured against production on 17 September 2026, three runs each: JFK→LHR in 1.34–2.84s, DUB→STN in 1.67–1.86s, a LAX→NRT round trip for two adults in 1.68–2.76s, and a nonstop business-class search in 1.78s.
Errors
A 400 names what is wrong — a malformed airport code, a departure date in the past, a missing required field, or an unrecognised one, because the body is a strict object: {"error":"Unrecognized key: \"sortBy\""}. A 401 means the key is missing or invalid.