June 15, 2026 · 7 min read · Data
IATA codes lie: a city has many airports, but APIs return one.
A user asks "nearest airport to London." Your API returns LHR. The user is staying near Stansted. They book a cab to Heathrow, spend three hours and £60, and write your product a one-star review. The principal-airport approximation is correct on average and wrong specifically — and specifically is what matters for trip planning.
Cities with multiple airports
A surprising number of major cities have more than one commercial airport, and the choice between them depends on the route, the airline, and where in the city the traveler is staying.
- London (6): LHR (Heathrow, west, the big one), LGW (Gatwick, south, low-cost long-haul), STN (Stansted, north, Ryanair hub), LTN (Luton, north, easyJet hub), LCY (City Airport, business commuters), SEN (Southend, occasional charter).
- New York (3): JFK (international hub, Queens), LGA (domestic, closer to Manhattan), EWR (Newark, United hub, technically New Jersey).
- Tokyo (2): NRT (Narita, far, most international long-haul), HND (Haneda, close, more domestic plus growing international).
- Paris (2): CDG (Charles de Gaulle, north, most flights), ORY (Orly, south, more domestic and southern Europe).
- Moscow (3): SVO, DME, VKO.
- Berlin (1, post-2020): BER consolidated Tegel and Schönefeld. Worth knowing because old itinerary data still references TXL.
- Istanbul (2): IST (new mega-hub on European side, opened 2018), SAW (Sabiha Gökçen, Asian side, low-cost).
- Shanghai (2): PVG (Pudong, international), SHA (Hongqiao, mostly domestic plus Tokyo/Seoul).
- São Paulo (3): GRU (international), CGH (domestic), VCP (Campinas, low-cost).
- Rio (2): GIG (international), SDU (domestic, on the bay).
- Buenos Aires (2): EZE (international), AEP (domestic).
- Seoul (2): ICN (Incheon, international), GMP (Gimpo, domestic plus a few short-haul).
What the API returns by default
GET /v1/cities/london
{
"city_id": "london",
"name": "London",
"iso_alpha2": "GB",
"context": {
"airport": {
"iata": "LHR",
"name": "Heathrow",
"is_primary": true
}
}
}
The context.airport object exposes the principal
airport — the one most travelers default to, weighted by
international long-haul traffic. It's the right answer for
"what airport should I fly into" 70% of the time. It is not
the right answer for everyone.
Querying alternates
The /v1/airports endpoint returns the full list with structured metadata:
GET /v1/airports?city_id=london
[
{ "iata": "LHR", "name": "Heathrow", "is_primary": true, "distance_km": 24, "annual_pax_m": 79 },
{ "iata": "LGW", "name": "Gatwick", "is_primary": false, "distance_km": 45, "annual_pax_m": 46 },
{ "iata": "STN", "name": "Stansted", "is_primary": false, "distance_km": 60, "annual_pax_m": 28 },
{ "iata": "LTN", "name": "Luton", "is_primary": false, "distance_km": 50, "annual_pax_m": 16 },
{ "iata": "LCY", "name": "City", "is_primary": false, "distance_km": 11, "annual_pax_m": 4 },
{ "iata": "SEN", "name": "Southend", "is_primary": false, "distance_km": 60, "annual_pax_m": 1 }
]
Now your application can rank by traffic, by distance, by typical airline mix, or by ground-transit duration — which is what users actually care about, and which doesn't track distance.
Why distance-based selection fails
The naive heuristic — "return the airport closest to the city centroid" — produces wrong results in three predictable ways:
- Closest by km isn't closest by minutes. Heathrow is 24km from central London but 15 minutes by Elizabeth Line. Stansted is 60km but a 45-minute Express. City Airport is 11km but no direct rail. The metric the user cares about is door-to-door time, which depends on where they're staying.
- Domestic vs international flights load different airports. A user flying London → Edinburgh probably wants LCY or LHR (BA) or LGW (BA), and definitely doesn't want STN (Ryanair to Edinburgh departs at 6am). The right airport depends on the airline set for the route, not the destination's distance.
- Low-cost carriers sequester themselves. Ryanair operates almost exclusively from STN and LTN. easyJet skews LGW and LTN. Returning LHR for "cheapest flight to Barcelona" is wrong by definition.
The right shape for AI trip planners
For a trip-planning AI, the airport selection should be a function of:
- The route (origin city + destination city + carrier set)
- The user's neighborhood within the city
- Their cost vs convenience preference
- Time of day (LCY has limited evening flights)
The /v1/airports payload gives you the inputs. The selection logic stays in your product because it's the part that encodes your UX opinion. We don't try to make that decision for you — we just make sure you have the data you need to make it correctly.