Every airport and every airline carries two different codes, and mixing them up is one of the most common bugs in flight software. JFK and KJFK point at the same airport; BA and BAW point at the same airline — but they come from two different systems, follow different rules, and are used in different places. This post explains what IATA and ICAO codes actually are, where each one is used, and how to resolve either into full airport or airline data with one API call.

The two systems, in one paragraph

IATA (International Air Transport Association) codes are the short, passenger-facing ones you see on your boarding pass and bag tag: 3 letters for airports (JFK, LHR, SYD) and 2 letters for airlines (BA, AA, SQ). ICAO (International Civil Aviation Organization) codes are the longer, operational ones used by pilots, air traffic control, and flight plans: 4 letters for airports (KJFK, EGLL, YSSY) and 3 letters for airlines (BAW, AAL, SIA). IATA is for commerce and passengers; ICAO is for operations and aviation systems.

AirportAirline
IATA3 letters — JFK2 letters — BA
ICAO4 letters — KJFK3 letters — BAW
Used forTickets, bag tags, bookingFlight plans, ATC, ADS-B

An airport baggage-claim carousel, where every bag tag carries the airport's three-letter IATA code

Why airport codes differ: uniqueness and structure

The key practical difference is uniqueness. ICAO airport codes are globally unique and structured: the first letter (or two) encodes a region, so every code slots into a worldwide grid.

  • K — contiguous United States (KJFK, KLAX, KORD)
  • EG — United Kingdom (EGLL Heathrow, EGKK Gatwick)
  • LF — France, ED/ET — Germany, Y — Australia (YSSY Sydney), RJ — Japan

IATA airport codes have no structure — they're just memorable 3-letter labels, often derived from the city name (LAX, MIA), and they are not guaranteed globally unique in the same rigorous way. That's exactly why operational systems standardized on ICAO: a flight plan or an ATC handoff can't tolerate ambiguity, but a bag tag can. When you're storing airport identifiers in a database, ICAO is the safer primary key; treat IATA as a display/booking convenience.

A subtle trap: many US airports look like their IATA code with a K bolted on (JFK → KJFK, LAX → KLAX), which tempts people to convert by string manipulation. It works often enough to be dangerous and fails everywhere else — Hawaii and Alaska use P prefixes (PHNL for HNL), and outside the US there's no relationship at all (LHR → EGLL). Never derive one code from the other; look it up.

Airline codes add a third identifier: the callsign

Airlines carry the same IATA/ICAO split, plus one more piece: the telephony callsign, the spoken name used on the radio.

  • British Airways — IATA BA, ICAO BAW, callsign "SPEEDBIRD"
  • American Airlines — IATA AA, ICAO AAL, callsign "AMERICAN"
  • Singapore Airlines — IATA SQ, ICAO SIA, callsign "SINGAPORE"

This matters because different data sources speak different codes. A flight number on a schedule or ticket uses the IATA airline code (BA123). A callsign on an ADS-B feed or an ATC transcript uses the ICAO code (BAW123, spoken "Speedbird 123"). If you're joining a live tracking feed to a booking system, you're joining BAW to BA — and you need a lookup that knows both.

Resolving airport codes by API

SkyLink API's airports endpoint accepts either an ICAO or an IATA code — you pass whichever one you have, and get back the full airport record with runways, frequencies, and resolved country/region:

# By ICAO
curl "https://skylink-api.p.rapidapi.com/airports/search?icao=KJFK" \
  -H "X-RapidAPI-Key: $RAPIDAPI_KEY" \
  -H "X-RapidAPI-Host: skylink-api.p.rapidapi.com"

# The same airport, by IATA
curl "https://skylink-api.p.rapidapi.com/airports/search?iata=JFK" \
  -H "X-RapidAPI-Key: $RAPIDAPI_KEY" \
  -H "X-RapidAPI-Host: skylink-api.p.rapidapi.com"

Both return the same object, which conveniently echoes both codes so you can store the pair:

{
  "ident": "KJFK",
  "name": "John F. Kennedy International Airport",
  "iso_country": "US",
  "icao_code": "KJFK",
  "iata_code": "JFK",
  "search_code": "KJFK",
  "search_type": "ICAO"
}

Pass one of icao/iata, never both. This endpoint is the natural resolver when a user picks an airport from search results or when you have a code from a schedule row and need facility data.

An Airbus A330 parked at a jet bridge, with ICAO aircraft type codes stencilled on the apron stand

Resolving airline codes by API

The airlines endpoint works the same way — pass an ICAO (3-letter) or IATA (2-letter) code and get back the carrier, including that all-important callsign:

curl "https://skylink-api.p.rapidapi.com/airlines/search?iata=AA" \
  -H "X-RapidAPI-Key: $RAPIDAPI_KEY" \
  -H "X-RapidAPI-Host: skylink-api.p.rapidapi.com"
[
  {
    "name": "American Airlines",
    "iata": "AA",
    "icao": "AAL",
    "callsign": "AMERICAN",
    "country": "United States",
    "active": "Y",
    "logo": "https://media.skylinkapi.com/logos/AA.png"
  }
]

Two behaviors to code for. First, the airlines endpoint returns an array (usually one item), and an unknown code returns HTTP 200 with an empty array [], not a 404 — plan for a "carrier not found" placeholder, not an error state. Second, several fields (iata, icao, callsign) can be null for obscure or defunct carriers, so don't assume every airline has all three identifiers.

A practical pattern: normalize on ingest

The cleanest architecture resolves codes once, at the edge, and stores the full set. When a flight or booking enters your system with whatever code it happened to carry, look it up and persist the ICAO, IATA, and (for airlines) callsign together. From then on your internal joins are unambiguous: match ADS-B callsigns to bookings via the stored ICAO↔IATA airline pair, and key airports on ICAO while displaying IATA. Chain the airport/airline lookups with aircraft registration lookup and flight status and you can turn a single raw identifier — a tail number, a hex code, a flight number — into a fully labeled record.

SkyLink API gives you a free tier of 1,000 requests/month to test airport and airline lookups against, with paid plans starting at $18.59/mo once you're ready for production traffic. It's available through the free trial — sign up, grab a key, and resolve ICAO or IATA codes in a single call.