Free airport API

Airport codes, distances and routes as JSON. No key, no sign-up, open CORS.

Every airport, city, country and busy route on this site is also a JSON file under https://airportmiles.com/api/v1. The files are static: fetch them like any web page, from a browser, a server or an AI agent. Built from open data (OurAirports, Wikidata, US DOT / BTS, Eurostat, and the national offices of Canada, Brazil, Chile, Australia, Korea, Japan and India) and refreshed monthly; this version was built on 14 October 2026.

Files

Path under /api/v1 What
/index.jsonEvery code and slug that has a file, the file URL templates, counts
/airports/{iata}.jsonOne of 4,008 airports: codes, names, position, runways, passengers, nonstop routes with km and passengers, airlines, nearby airports
/routes/{iata}-{iata}.jsonOne of 2,785 busy routes (codes in alphabetical order): km, miles, nautical miles, flight time, EU261 / UK261 band, CO2, airlines, aircraft, passengers by month; on US domestic routes, average fares paid and a fare outlook; on Brazilian domestic routes, fares sold
/cities/{slug}.jsonOne of 70 cities with several airports: the airports, the city code, distances between them
/countries/{slug}.jsonOne of 233 countries: every airport with scheduled flights, busiest first
/openapi.jsonOpenAPI 3.1 description, for code generators and AI agents

Codes and slugs are lowercase. A route file exists only for the pairs in index.json; the whole airport list as one file is the CC0 dataset (JSON and CSV).

Quick start

Shell

curl https://airportmiles.com/api/v1/airports/lhr.json

JavaScript (browser or Node)

const res = await fetch('https://airportmiles.com/api/v1/routes/jfk-lhr.json')
const route = await res.json()
console.log(route.distance.km, route.flightTime.estimateMin)

Python

import requests

airport = requests.get('https://airportmiles.com/api/v1/airports/lhr.json',
                       headers={'User-Agent': 'my-app/1.0'}).json()
print(airport['airport']['icao'], len(airport['routes']))

What a file looks like

/api/v1/airports/lju.json, shortened:

{
  "api": "AirportMiles API v1",
  "generated": "2026-10-14",
  "docs": "https://airportmiles.com/api",
  "self": "https://airportmiles.com/api/v1/airports/lju.json",
  "page": "https://airportmiles.com/airport/lju",
  "licence": "CC0-1.0",
  "licenceNote": "Fields a source in \"sources\" covers keep that source's licence: name the source when you reuse them.",
  "airport": {
    "iata": "LJU",
    "icao": "LJLJ",
    "name": "Ljubljana Jože Pučnik Airport",
    "municipality": "Zgornji Brnik",
    "city": "Ljubljana",
    "multiAirportCity": null,
    "country": {
      "code": "SI",
      "name": "Slovenia",
      "self": "https://airportmiles.com/api/v1/countries/slovenia.json",
      "page": "https://airportmiles.com/airports/slovenia"
    },
    "region": "Cerklje na Gorenjskem Municipality",
    "continent": "EU",
    "latitude": 46.2237,
    "longitude": 14.4576,
    "elevationM": 388,
    "size": "large",
    "wikidata": "Q1109558",
    "website": "http://www.lju-airport.si/",
    "wikipedia": "https://en.wikipedia.org/wiki/Ljubljana_Jo%C5%BEe_Pu%C4%8Dnik_Airport",
    "opened": 1963,
    "operator": [
      "Fraport"
    ],
    "runways": [
      {
        "ids": "12/30",
        "lengthM": 3300,
        "widthM": 45,
        "surface": "Asphalt",
        "lighted": true
      }
    ]
  },
  "passengers": {
    "count": 1591308,
    "previousYear": 1437662,
    "period": "2025",
    "source": "eurostat",
    "yearToDate": {
      "months": "2026-01…2026-07",
      "count": 998794,
      "sameMonthsYearBefore": 870784
    }
  },
  "routes": [
    {
      "to": {
        "iata": "IST",
        "icao": "LTFM",
        "name": "İstanbul Airport",
        "city": "Istanbul",
        "country": "TR",
        "latitude": 41.2749,
        "longitude": 28.7321,
        "self": "https://airportmiles.com/api/v1/airports/ist.json"
      },
      "km": 1272,
      "passengers": 190788,
      "nationalSource": null,
      "self": null,
      "page": null
    },
    {
      "to": {
        "iata": "FRA",
        "icao": "EDDF",
        "name": "Frankfurt Main Airport",
        "city": "Frankfurt",
        "country": "DE",
        "latitude": 50.0267,
        "longitude": 8.5584,
        "self": "https://airportmiles.com/api/v1/airports/fra.json"
      },
      "km": 609,
      "passengers": 137259,
      "nationalSource": null,
      "self": null,
      "page": null
    },
    "… 18 more"
  ],
  "airlines": null,
  "punctuality": null,
  "cityAirports": [],
  "nearby": [
    {
      "iata": "KLU",
      "icao": "LOWK",
      "name": "Klagenfurt Airport",
      "city": "Klagenfurt am Wörthersee",
      "country": "AT",
      "latitude": 46.6425,
      "longitude": 14.3377,
      "self": "https://airportmiles.com/api/v1/airports/klu.json",
      "km": 47
    }
  ],
  "sources": [
    {
      "id": "ourairports",
      "name": "OurAirports",
      "url": "https://ourairports.com/data/",
      "licence": "Public domain",
      "fields": [
        "iata",
        "icao",
        "name",
        "municipality",
        "country",
        "region",
        "latitude",
        "longitude",
        "elevationM",
        "size",
        "runways",
        "website",
        "wikipedia"
      ]
    },
    "… 4 more"
  ]
}

Any two airports

Route files cover the busiest pairs with traffic data. For any other pair, take both airports' coordinates from their files and compute the distance; the calculator does the same in the browser, with stops.

// Any two airports: great circle on a sphere (R = 6,371 km), the EU261 method.
// Within about 0.5% of the WGS-84 distance the route files carry.
const rad = d => d * Math.PI / 180
function km(a, b) {
  const h = Math.sin(rad(b.latitude - a.latitude) / 2) ** 2
    + Math.cos(rad(a.latitude)) * Math.cos(rad(b.latitude)) * Math.sin(rad(b.longitude - a.longitude) / 2) ** 2
  return 2 * 6371 * Math.asin(Math.sqrt(h))
}

Licence and fair use

  • Airport, city, country and distance fields: CC0, use them for anything, no attribution needed.
  • Traffic, punctuality and fare fields keep their source's terms. Each file lists them in sources with the fields they cover: US DOT / BTS is public domain, JAC (Chile) CC0; Eurostat, UK DESNZ, Statistics Canada, ANAC, Incheon Airport, Korea Airports Corporation, BITRE, MLIT and DGCA figures need the source named. Details on Sources.
  • No time zones: their source (timezone-boundary-builder) is under the ODbL, so they stay on the pages.
  • No key and no quota. Cache what you fetch, keep requests reasonable, and send a User-Agent that names your app. v1 keeps its fields; a breaking change would come as v2.

Questions or a field you need: [email protected].

Questions

Yes: AirportMiles publishes 4,008 airports, 2,785 routes, 70 cities and 233 countries as static JSON files at https://airportmiles.com/api/v1. No key, no sign-up, no rate plan.