Ticket search

Runnable examples for searching flight ticket prices: cheapest and fastest options, full itinerary details, and multi-passenger comparisons. See the Flight Tickets reference for field definitions. Uses IATA codes (not ICAO). Results are cached for 1 hour — prices are indicative and may change at booking time.

#QuestionData used
1Find cheapest and fastest options for JFK → LAXGET /tickets/search
2Show full itinerary with layover details for LHR → JFKGET /tickets/search
3Search for 2 passengers LHR → CDG — compare all optionsGET /tickets/search

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. Cheapest and fastest: JFK → LAX

Question: What are the cheapest and fastest ticket options on the JFK–LAX route?

The API returns results sorted cheapest-first. Find the fastest option by scanning total_duration_min.

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"


def fetch_tickets(
    origin: str,
    destination: str,
    date: str | None = None,
    passengers: int = 1,
) -> dict | None:
    params: dict[str, str | int] = {
        "origin": origin,
        "destination": destination,
        "passengers": passengers,
    }
    if date:
        params["date"] = date
    r = requests.get(
        f"{BASE}/tickets/search",
        headers=HEADERS,
        params=params,
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def fmt_mins(minutes: int | None) -> str:
    if minutes is None:
        return "—"
    return f"{minutes // 60}h {minutes % 60:02d}m"


def stops_label(stops: int) -> str:
    return "Nonstop" if stops == 0 else f"{stops} stop(s)"


def flight_summary(flight: dict) -> str:
    legs = flight.get("legs", [])
    first_leg = legs[0] if legs else {}
    return (
        f"${flight.get('price_usd', 0):.2f}  ·  "
        f"{stops_label(flight.get('stops', 0))}  ·  "
        f"{fmt_mins(flight.get('total_duration_min'))}  ·  "
        f"{first_leg.get('flight_number', '—')} ({first_leg.get('airline', '—')})"
    )


def main() -> None:
    data = fetch_tickets("JFK", "LAX")
    if not data:
        console.print("[red]No ticket data returned.[/red]")
        return

    flights = data.get("flights", [])
    if not flights:
        console.print("[yellow]No flights available for JFK → LAX.[/yellow]")
        return

    cheapest = flights[0]
    fastest = min(flights, key=lambda f: f.get("total_duration_min") or 99999)

    console.print(
        Panel(
            f"[bold green]Cheapest[/bold green]\n{flight_summary(cheapest)}",
            title="JFK → LAX",
            style="green",
        )
    )

    if fastest is not cheapest:
        console.print(
            Panel(
                f"[bold cyan]Fastest[/bold cyan]\n{flight_summary(fastest)}",
                title="JFK → LAX",
                style="cyan",
            )
        )
    else:
        console.print("[dim]Cheapest option is also the fastest.[/dim]")


if __name__ == "__main__":
    main()

Output: Two panels — the cheapest option and the fastest option — each showing price, stop count, total duration, and the first leg's flight number and airline. When cheapest equals fastest, only one panel is shown.


2. Full itinerary with layover details: LHR → JFK

Question: What does a connecting itinerary look like, including each leg and layover wait times?

Find the first connecting option in the results and display each leg as a row, then list layover stops with wait times.

import os

import requests
from rich.console import Console
from rich.panel import Panel
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"


def fetch_tickets(origin: str, destination: str) -> dict | None:
    r = requests.get(
        f"{BASE}/tickets/search",
        headers=HEADERS,
        params={"origin": origin, "destination": destination, "passengers": 1},
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def fmt_mins(minutes: int | None) -> str:
    if minutes is None:
        return "—"
    return f"{minutes // 60}h {minutes % 60:02d}m"


def print_itinerary(flight: dict, label: str) -> None:
    console.print(
        Panel(
            f"[bold]{label}[/bold]  ·  ${flight.get('price_usd', 0):.2f}  ·  "
            f"{fmt_mins(flight.get('total_duration_min'))}",
            style="blue",
        )
    )

    legs_table = Table(show_header=True, show_lines=True)
    legs_table.add_column("Airline", style="cyan")
    legs_table.add_column("Flight")
    legs_table.add_column("From")
    legs_table.add_column("To")
    legs_table.add_column("Departs")
    legs_table.add_column("Arrives")
    legs_table.add_column("Duration")

    for leg in flight.get("legs", []):
        legs_table.add_row(
            leg.get("airline", "—"),
            leg.get("flight_number", "—"),
            f"{leg.get('departure_airport', '—')} ({leg.get('departure_airport_name', '—')[:20]})",
            f"{leg.get('arrival_airport', '—')} ({leg.get('arrival_airport_name', '—')[:20]})",
            leg.get("departure_time", "—"),
            leg.get("arrival_time", "—"),
            fmt_mins(leg.get("duration_min")),
        )

    console.print(legs_table)

    layovers = flight.get("layovers", [])
    if layovers:
        console.print("[bold]Layovers[/bold]")
        for lw in layovers:
            console.print(
                f"  {lw.get('airport', '—')}  {lw.get('airport_name', '—')}  "
                f"[yellow]{fmt_mins(lw.get('duration_min'))} wait[/yellow]"
            )


def main() -> None:
    data = fetch_tickets("LHR", "JFK")
    if not data:
        console.print("[red]No ticket data returned.[/red]")
        return

    flights = data.get("flights", [])
    if not flights:
        console.print("[yellow]No flights available for LHR → JFK.[/yellow]")
        return

    connecting = next((f for f in flights if f.get("stops", 0) > 0), None)

    if connecting:
        print_itinerary(connecting, "Connecting Itinerary — LHR → JFK")
    else:
        console.print("[dim]No connecting flights in results — showing cheapest nonstop.[/dim]")
        print_itinerary(flights[0], "Nonstop — LHR → JFK")


if __name__ == "__main__":
    main()

Output: An itinerary card showing each leg (airline, flight number, airports, departure/arrival times, duration) followed by a layover list with wait times per stop. Falls back to the cheapest nonstop if no connecting options are available.


3. All options for 2 passengers: LHR → CDG

Question: What are all available ticket options for 2 passengers on LHR–CDG?

Display every returned option as a comparison table. Show original currency when it differs from USD.

import os

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"


def fetch_tickets(
    origin: str, destination: str, passengers: int
) -> dict | None:
    r = requests.get(
        f"{BASE}/tickets/search",
        headers=HEADERS,
        params={
            "origin": origin,
            "destination": destination,
            "passengers": passengers,
        },
        timeout=(10, 15),
    )
    if r.status_code == 404:
        return None
    r.raise_for_status()
    return r.json()


def fmt_mins(minutes: int | None) -> str:
    if minutes is None:
        return "—"
    return f"{minutes // 60}h {minutes % 60:02d}m"


def stops_label(stops: int) -> str:
    return "Nonstop" if stops == 0 else f"{stops} stop(s)"


def main() -> None:
    passengers = 2
    data = fetch_tickets("LHR", "CDG", passengers=passengers)
    if not data:
        console.print("[red]No ticket data returned.[/red]")
        return

    flights = data.get("flights", [])
    if not flights:
        console.print("[yellow]No flights available for LHR → CDG.[/yellow]")
        return

    table = Table(
        title=f"LHR → CDG — {len(flights)} option(s) for {passengers} passengers",
        show_lines=True,
    )
    table.add_column("#", justify="right", style="dim")
    table.add_column("Price (USD)", justify="right", style="bold green")
    table.add_column("Price/pax", justify="right")
    table.add_column("Duration", justify="center")
    table.add_column("Stops", justify="center")
    table.add_column("First Flight")

    for i, flight in enumerate(flights, start=1):
        price = flight.get("price_usd", 0.0)
        per_pax = price / passengers if passengers else price

        orig_price = flight.get("original_price")
        orig_currency = flight.get("original_currency", "USD")
        price_cell = f"${price:.2f}"
        if orig_currency and orig_currency != "USD" and orig_price:
            price_cell += f"\n[dim]({orig_price:.0f} {orig_currency})[/dim]"

        legs = flight.get("legs", [])
        first = legs[0] if legs else {}
        first_flight = (
            f"{first.get('flight_number', '—')} {first.get('airline', '—')}"
        )

        table.add_row(
            str(i),
            price_cell,
            f"${per_pax:.2f}",
            fmt_mins(flight.get("total_duration_min")),
            stops_label(flight.get("stops", 0)),
            first_flight,
        )

    console.print(table)
    console.print(
        "[dim]Prices are market snapshots — confirm at booking. "
        "Results cached for 1 hour.[/dim]"
    )


if __name__ == "__main__":
    main()

Output: A table listing every available option with total price, per-passenger price, duration, stop count, and first leg flight number. Original currency is shown beneath the USD price when it differs.