Error handling

Caching and monitoring: Caching & monitoring.

Platform errors (401, 403, 422, 429, 5xx, retry/backoff, rate-limit headers): Error Handling.

Flight time: 422 — unrecognised airport codes

GET /ml/flight-time validates that both from and to resolve to known airports. An unknown or malformed code returns 422 with a detail message identifying which code failed.

CodeMeaningFix
422from or to not recognisedUse a valid ICAO (4-letter, e.g. KJFK) or IATA (3-letter, e.g. JFK) code. Resolve via Airport Search.
404No route data for this pairThe model lacks enough historical data for this city pair. Show "Estimate unavailable."

Note: The result is a statistical average derived from historical operational data — not a real-time forecast. Wind and live en-route conditions are not model inputs. Disclose this when presenting estimates to passengers or schedulers.

import os
import requests

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"


def fetch_flight_time(origin: str, destination: str, aircraft: str | None = None) -> dict | None:
    """
    Fetch ML flight time estimate. Returns None on 404 (no data for pair).
    Raises ValueError on 422 (invalid airport code).
    """
    params: dict[str, str] = {"from": origin, "to": destination}
    if aircraft:
        params["aircraft"] = aircraft
    r = requests.get(
        f"{BASE}/ml/flight-time",
        headers=HEADERS,
        params=params,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    if r.status_code == 422:
        detail = r.json().get("detail", "invalid airport code")
        raise ValueError(f"422 Unprocessable: {detail}")
    r.raise_for_status()
    return r.json()


# Valid request — KJFK to KLAX
if __name__ == "__main__":
    data = fetch_flight_time("KJFK", "KLAX", aircraft="B738")
    if data:
        print(
            f"Estimated: {data['estimated_hours_display']}  "
            f"({data['min_minutes']}–{data['max_minutes']} min range)"
        )
        print("Statistical average — actual time varies with winds and routing.")
    else:
        print("No estimate available for this route.")

    try:
        fetch_flight_time("ZZZZ", "KLAX")
    except ValueError as exc:
        print(f"Caught expected error: {exc}")

Carbon: 422 — missing required parameters

GET /carbon/estimate requires either an airport pair (departure_icao + arrival_icao) or a callsign. Omitting both returns 422.

CodeMeaningFix
422Neither airport pair nor callsign suppliedProvide departure_icao + arrival_icao, or a callsign.
422Unrecognised airport codeEnsure ICAO codes are valid 4-letter identifiers. Resolve via Airport Search.
404No emissions data for this pairRoute is outside model coverage. Show "Estimate unavailable."

RFI disclosure: Passing include_rfi=true applies a Radiative Forcing Index multiplier (~2×) to the base CO₂ figure. When rfi_applied: true appears in the response, disclose in the UI that the displayed figure includes climate-forcing effects beyond CO₂ alone (per ICAO Doc 9988 guidance).

import os
import requests

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"


def fetch_carbon(
    departure_icao: str | None = None,
    arrival_icao: str | None = None,
    callsign: str | None = None,
    passengers: int = 1,
    include_rfi: bool = False,
) -> dict | None:
    """
    Fetch carbon estimate. Requires departure_icao+arrival_icao or callsign.
    Returns None on 404. Raises ValueError on 422.
    """
    params: dict[str, str | int] = {
        "passengers": passengers,
        "include_rfi": str(include_rfi).lower(),
    }
    if departure_icao:
        params["departure_icao"] = departure_icao
    if arrival_icao:
        params["arrival_icao"] = arrival_icao
    if callsign:
        params["callsign"] = callsign

    r = requests.get(
        f"{BASE}/carbon/estimate",
        headers=HEADERS,
        params=params,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    if r.status_code == 422:
        detail = r.json().get("detail", "validation error")
        raise ValueError(f"422 Unprocessable: {detail}")
    r.raise_for_status()
    return r.json()


# 1. Attempt without required params — expect 422
if __name__ == "__main__":
    try:
        fetch_carbon()
    except ValueError as exc:
        print(f"Missing params error: {exc}")

    data = fetch_carbon(departure_icao="KJFK", arrival_icao="KLAX", passengers=1)
    if data:
        co2 = data.get("co2_kg_per_passenger", 0.0)
        rfi = data.get("rfi_applied", False)
        print(f"CO₂/passenger: {co2:.1f} kg  (RFI applied: {rfi})")
        if rfi:
            print(
                "Disclosure: figure includes radiative forcing effects "
                "(~2× base CO₂, ICAO Doc 9988)."
            )
    else:
        print("No estimate available for this route.")

For transient failures (429, 5xx), use the retry helper on Error Handling.


Related: Flight Time · Carbon Emissions · Caching & monitoring · Error Handling