Error handling
Caching and monitoring: Caching & monitoring.
Platform errors (401, 403, 422, 429, 5xx, retry/backoff, rate-limit headers): Error Handling.
Empty results are not errors
count: 0 with flights: [] is a valid response. It means no seats were found for the requested itinerary on that date — not a client bug or server failure. Show a no-availability state in the UI rather than an error banner.
{
"origin": "JFK",
"destination": "LAX",
"date": "2026-08-14",
"passengers": 1,
"count": 0,
"flights": []
}| Status | Meaning | UI response |
|---|---|---|
200 with count > 0 | Results available | Show flight list |
200 with count: 0 | No availability | Show "No flights found for this route and date." |
422 | Invalid parameters | Fix the request — do not surface to passengers |
429 | Rate limit exceeded | Back off and retry — see retry helper |
IATA codes only
This endpoint accepts IATA 3-letter codes (JFK, LAX, LHR) — not ICAO. Passing a 4-letter ICAO code (KJFK) returns a 422. Resolve codes first with Airport Search.
422 — validation errors
Returned when origin or destination are missing, blank, or fail the IATA format check.
| Field | Common cause |
|---|---|
origin | Missing, blank, or a 4-letter ICAO code passed instead of IATA |
destination | Same as above |
passengers | Value outside the 1–9 range |
Prices are indicative
Quotes reflect a market snapshot at the time of search, not live airline inventory. Seats shown may sell out or change price between search and booking. Disclose this to passengers in any UI that shows prices (for example: "Prices may change at booking").
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 search_tickets(
origin: str,
destination: str,
date: str | None = None,
passengers: int = 1,
) -> dict:
"""
Search tickets. Returns the full response dict including count and flights.
Raises ValueError on 422. Returns count:0/flights:[] for no availability.
"""
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 == 422:
detail = r.json().get("detail", "validation error")
raise ValueError(f"422 Unprocessable: {detail}")
r.raise_for_status()
return r.json()
def display_results(data: dict) -> None:
flights = data.get("flights", [])
origin = data.get("origin", "?")
dest = data.get("destination", "?")
if not flights:
# count:0 is valid — show a user-friendly empty state
print(f"No flights found for {origin} → {dest} on {data.get('date', '?')}.")
print("Try a different date or check nearby airports.")
return
cheapest = flights[0]
price = cheapest.get("price_usd", 0.0)
duration = cheapest.get("total_duration_min", 0)
stops = cheapest.get("stops", 0)
print(
f"{origin} → {dest} · {len(flights)} option(s) · "
f"from ${price:.2f} · {duration // 60}h {duration % 60:02d}m · "
f"{'Nonstop' if stops == 0 else f'{stops} stop(s)'}"
)
print("Prices may change at booking.")
if __name__ == "__main__":
data = search_tickets("JFK", "LAX")
display_results(data)
try:
search_tickets("KJFK", "KLAX")
except ValueError as exc:
print(f"Caught expected error: {exc}")For transient failures (429, 5xx), use the retry helper on Error Handling.
Related: Flight Tickets · Airport Search · Caching & monitoring · Error Handling