Aircraft lookup

Runnable examples for resolving tail numbers and ICAO hex codes to aircraft metadata. See the full Aircraft Lookup reference for field definitions and response shape.

#QuestionData used
1What aircraft type and operator flies tail number N636JB?/aircraft/registration/{registration}
2Get a photo of an aircraft by tail number for a fleet display/aircraft/registration/{registration} with photos=true
3Batch-resolve three tail numbers to types and operators/aircraft/registration/{registration}

Requirements

Auth
x-api-key on every request (direct subscription). Learn more →

Install

The scripts below use requests for API calls and rich for terminal output. Install once:

pip install requests rich

1. Resolve a tail number to aircraft type and operator

Question: What type of aircraft is N636JB, and who operates it?

Registry lookups are the starting point for fleet composition analysis, photo displays, and performance chaining. The found field tells you definitively whether the registration exists in the SkyLink aircraft registry.

import os

import requests
from rich.console import Console
from rich.panel import Panel

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

REGISTRATION = "N636JB"


def fetch_aircraft(registration: str) -> dict | None:
    r = requests.get(
        f"{BASE}/aircraft/registration/{registration}",
        headers=HEADERS,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    data = fetch_aircraft(REGISTRATION)

    if data is None or not data.get("found"):
        console.print(f"[yellow]⚠ Registration {REGISTRATION} not found in registry.[/yellow]")
        return

    ac = data["aircraft"]
    lines = [
        f"[bold]Registration:[/bold]  {ac['registration']}",
        f"[bold]ICAO24:[/bold]        {ac['icao24']}",
        f"[bold]ICAO Type:[/bold]     {ac['icao_type']}",
        f"[bold]Full Name:[/bold]     {ac['type_name']}",
        f"[bold]Operator:[/bold]      {ac['owner_operator']}",
    ]
    console.print(Panel("\n".join(lines), title=f"Aircraft — {REGISTRATION}", border_style="cyan"))


if __name__ == "__main__":
    main()

Output: A panel showing registration, hex code, ICAO type designator, full type name, and operator.

Tip: Cache registry responses for up to 24 hours — aircraft registration data changes infrequently, and repeated lookups for the same tail number consume quota unnecessarily.


2. Get an aircraft photo from a tail number

Question: Does N636JB have a community photo I can display in a fleet card?

Pass photos=true to include the photos array in the response. Photos are community-sourced and may not always be present — check the array length before rendering.

import os

import requests
from rich.console import Console
from rich.panel import Panel

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

REGISTRATION = "N636JB"


def fetch_aircraft_with_photos(registration: str) -> dict | None:
    r = requests.get(
        f"{BASE}/aircraft/registration/{registration}",
        headers=HEADERS,
        params={"photos": "true"},
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def main() -> None:
    data = fetch_aircraft_with_photos(REGISTRATION)

    if data is None or not data.get("found"):
        console.print(f"[yellow]⚠ Registration {REGISTRATION} not found.[/yellow]")
        return

    ac = data["aircraft"]
    photos = ac.get("photos") or []

    if not photos:
        console.print(f"[yellow]No photos available for {REGISTRATION}.[/yellow]")
        console.print("Photos are community-sourced and may not be present for every aircraft.")
        return

    first_photo = photos[0]["image"]
    icao_type = ac["icao_type"]

    lines = [
        f"[bold]Registration:[/bold]  {ac['registration']}",
        f"[bold]Type:[/bold]          {ac['type_name']}",
        f"[bold]Operator:[/bold]      {ac['owner_operator']}",
        f"[bold]Photo URL:[/bold]     [link={first_photo}]{first_photo}[/link]",
        f"[bold]Total photos:[/bold]  {len(photos)}",
    ]
    console.print(Panel("\n".join(lines), title="Fleet Card", border_style="blue"))
    console.print(
        f"\n[dim]Chain to /aircraft/performance/{icao_type} for performance specs.[/dim]"
    )


if __name__ == "__main__":
    main()

Output: A panel with the first photo URL, type, and operator. If no photos are available, a warning is printed.

Next step: Chain to /aircraft/performance/{icao_type} using the icao_type field to pull performance specs alongside the photo.


3. Batch lookup: resolve multiple tail numbers to types

Question: Given a list of tail numbers from different registries, what types and operators are they?

Use ThreadPoolExecutor to fetch registrations concurrently. Gracefully handle found=false for unregistered or unknown aircraft.

import os
from concurrent.futures import ThreadPoolExecutor, as_completed

import requests
from rich.console import Console
from rich.table import Table

console = Console()

HEADERS = {
    "X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
    "X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"

REGISTRATIONS = ["N636JB", "G-EUUU", "D-AIBL"]


def fetch_aircraft(registration: str) -> tuple[str, dict | None]:
    r = requests.get(
        f"{BASE}/aircraft/registration/{registration}",
        headers=HEADERS,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return registration, None
    r.raise_for_status()
    return registration, r.json()


def main() -> None:
    results: dict[str, dict | None] = {}

    with ThreadPoolExecutor(max_workers=5) as pool:
        futures = {pool.submit(fetch_aircraft, reg): reg for reg in REGISTRATIONS}
        for future in as_completed(futures):
            reg, data = future.result()
            results[reg] = data

    table = Table(title="Batch Aircraft Lookup", border_style="cyan")
    table.add_column("Registration", style="bold")
    table.add_column("Found", justify="center")
    table.add_column("ICAO Type")
    table.add_column("Full Name")
    table.add_column("Operator")

    for reg in REGISTRATIONS:
        data = results.get(reg)
        if data is None or not data.get("found"):
            table.add_row(reg, "[red]✗[/red]", "—", "—", "—")
        else:
            ac = data["aircraft"]
            table.add_row(
                ac["registration"],
                "[green]✓[/green]",
                ac["icao_type"],
                ac["type_name"],
                ac["owner_operator"],
            )

    console.print(table)


if __name__ == "__main__":
    main()

Output: A table with one row per registration: Registration | Found | ICAO Type | Full Name | Operator. Unresolved registrations show ✗ and dashes.