API

No API key or authentication is required.

GET /flights

Returns one page of flights, newest first. Up to limit flights per response (default and max 1000); pass offset to skip ahead. Follow the next URL in the response, requesting it as-is, until it's null, to iterate the whole dataset.

By default each flight contains only url, a direct link to the .igc file. Use fields to ask for more.

Query parameters

ParamDefaultDescription
limit1000Flights to return, 11000
offset0Number of flights to skip
fieldsurlWhich flight fields to return (see below)

Choosing fields

fields takes a comma-separated list of the field names in the table below — for example fields=id,flight_date,url. Pass fields=all for every field. Only what you ask for is read from the database and sent back, so requesting less is faster and cheaper for both of us. An unrecognised field name is an error (400) rather than being ignored, so typos don't silently return the wrong shape.

Fields come back in the order listed in the table, whatever order you ask for them in, and fields is carried over into the next URL — so paging keeps your selection without you re-adding it.

Changed: this endpoint used to return every field by default. If you have an existing integration that reads anything other than url, add ?fields=all to restore the old response, or better, list just the fields you use.

Examples

curl https://open-igc-database.pages.dev/flights
curl "https://open-igc-database.pages.dev/flights?fields=id,flight_date,duration_s,url"
curl "https://open-igc-database.pages.dev/flights?fields=all&limit=10"

Response fields

FieldTypeDescription
flightsarrayFlight objects for this page (fields below)
totalnumberTotal number of flights in the database
limitnumberEffective limit used for this page
offsetnumberEffective offset used for this page
nextstring | nullURL for the next page, or null if this was the last one

Every name below is a valid fields value. Each object in flights contains exactly the ones you selected:

FieldTypeDescription
idstringSHA-256 of the IGC file (also the file key)
flight_datestringFlight date, YYYY-MM-DD
pilot_namestring | nullPilot name from the IGC header
takeoff_latnumberTakeoff latitude
takeoff_lonnumberTakeoff longitude
landing_latnumberLanding latitude
landing_lonnumberLanding longitude
duration_snumberFlight duration in seconds
max_altitudenumber | nullMax altitude in metres
point_countnumberNumber of GPS fixes
glider_typestring | nullGlider model from the IGC header
size_bytesnumberSize of the IGC file in bytes
takeoff_hournumber | nullLocal hour of day at takeoff, 0–23 (null for flights stored before this field existed)
takeoff_tzstring | nullIANA time zone at takeoff, e.g. Europe/Paris
urlstringDirect link to the .igc file (the default; see note below)

The file behind url is stored and served gzip-compressed (Content-Encoding: gzip). Browsers and fetch decode this automatically; with curl or wget add --compressed or you'll get the raw gzip bytes:

curl --compressed -o flight.igc "https://…/a1b2c3….igc"

Sample response

Default (GET /flights):

{
  "flights": [
    { "url": "https://…/a1b2c3….igc" },
    { "url": "https://…/d4e5f6….igc" }
  ],
  "total": 4213,
  "limit": 1000,
  "offset": 0,
  "next": "https://…/flights?limit=1000&offset=1000"
}

With ?fields=all (the flights array only, other fields unchanged):

  "flights": [
    {
      "id": "a1b2c3…",
      "flight_date": "2024-06-15",
      "pilot_name": "Jane Doe",
      "takeoff_lat": 45.9237,
      "takeoff_lon": 6.8694,
      "landing_lat": 45.8992,
      "landing_lon": 6.1294,
      "duration_s": 5432,
      "max_altitude": 2850,
      "point_count": 5431,
      "glider_type": "Ozone Zeno 2",
      "size_bytes": 184320,
      "uploaded_at": 1718460000,
      "takeoff_hour": 14,
      "takeoff_tz": "Europe/Paris",
      "url": "https://…/a1b2c3….igc"
    }
  ],

POST /flights

Upload a single .igc file, sent as the raw request body. The file is parsed, validated and stored. Flights are deduplicated by content, so re-uploading the same track is safe.

Add ?anonymous=1 to strip identifying headers (pilot, crew, glider registration, competition id) before storing and list the pilot as Anonymous.

Example

curl --data-binary @flight.igc -H "Content-Type: application/octet-stream" https://open-igc-database.pages.dev/flights

Responses

StatusMeaning
201Flight added
200Duplicate — this track was already stored
400Empty body or not a valid IGC track (see error)

On success the response is the full flight object — every field listed above, as with ?fields=all — plus a status field of "added" or "duplicate". There is no fields param here; it's a single row, so it's always sent in full.

Sample response

{
  "status": "added",
  "id": "a1b2c3…",
  "flight_date": "2024-06-15",
  "pilot_name": "Jane Doe",
  "takeoff_lat": 45.9237,
  "takeoff_lon": 6.8694,
  "landing_lat": 45.8992,
  "landing_lon": 6.1294,
  "duration_s": 5432,
  "max_altitude": 2850,
  "point_count": 5431,
  "glider_type": "Ozone Zeno 2",
  "size_bytes": 184320,
  "uploaded_at": 1718460000,
  "takeoff_hour": 14,
  "takeoff_tz": "Europe/Paris",
  "url": "https://…/a1b2c3….igc"
}