There is no self-serve Skyscanner API key. Access is by application, Skyscanner approves partners one by one, and the docs name no price. To get fares for a few routes without that, you read what Skyscanner shows on its route pages. Our API does that, and the script below logs the fares to a CSV.
What Skyscanner's API is for
Skyscanner's travel API is for established travel businesses with a large audience. You apply to the Partnerships team, and approved partners get an account manager and earn commission. Flights come in two kinds: Live Prices run a real search across suppliers, and Indicative Prices are cached fares that the docs say can be "up to 4 days old". Partners get both. If you run a travel site and want bookable prices on your dates and cabin, apply there.
Cheapest fares by route with ToolzerHub
We make ToolzerHub. Our Skyscanner API reads Skyscanner's public route pages. /v1/skyscanner/route takes two Skyscanner place codes, a city (lond, nyca) or an airport (lhr, jfk), and costs 1 credit a call with the x-api-key header.
export TOOLZERHUB_API_KEY=your_key
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
"https://api.toolzerhub.com/v1/skyscanner/route?origin=lond&destination=nyca"
The cheapest of the 16 quotes for London to New York, inside data.deals, with images, ids and tracking parameters cut:
{
"price": 210,
"formatted_price": "£210",
"direct": false,
"legs": [
{
"date": "2026-11-23",
"quoted_at": "2026-10-21T20:14Z",
"origin": { "sky_code": "LGW", "name": "London Gatwick" },
"destination": { "sky_code": "JFK", "name": "New York John F. Kennedy" },
"carrier_name": "Ryanair"
}
],
"deep_link_path": "/transport/flights/LGW/JFK/20261123?locale=en-GB&market=UK¤cy=GBP"
}
Each quote is one-way, for one date, with the time Skyscanner saw the price. Next to the quotes, the response has cheapest_by_month for 12 months, nearby_airports with a price each (Newark £220, LaGuardia £288 here) and the airlines flying the route direct.
Prices are in GBP from Skyscanner's UK site, and there are no date, cabin or passenger parameters: you get the quotes the page shows. Place names don't work, only codes; every response lists sky_code for its airports and nearby airports, which you can pass back in.
Log fares for the routes you watch
The script takes a list of routes, appends every quote to a CSV with its age in hours and a link, and prints the cheapest price by month. Run it from cron once a day to build a fare history, and drop repeats on origin, destination, date and quoted_at. Save it as skyscanner_fares.py and install requests (pip install requests).
import csv
import os
import sys
import time
from datetime import datetime, timezone
import requests
URL = "https://api.toolzerhub.com/v1/skyscanner/route"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["fetched_at", "origin", "destination", "date", "price", "currency", "direct",
"carrier", "quoted_at", "age_hours", "link"]
def route(origin, destination, tries=3):
# 429, 5xx and dropped connections are retried; failed calls cost no credits.
params = {"origin": origin, "destination": destination}
for attempt in range(tries):
last = attempt == tries - 1
try:
r = requests.get(URL, headers=HEADERS, params=params, timeout=90)
except requests.RequestException:
if last:
raise
time.sleep(10 * (attempt + 1))
continue
if r.status_code in (429, 500, 502, 503, 504) and not last:
time.sleep(10 * (attempt + 1))
continue
r.raise_for_status()
return r.json()["data"]
def age_hours(quoted_at, now):
quoted = datetime.strptime(quoted_at, "%Y-%m-%dT%H:%MZ").replace(tzinfo=timezone.utc)
return round((now - quoted).total_seconds() / 3600, 1)
def main(routes, out="fares.csv"):
now = datetime.now(timezone.utc)
new_file = not os.path.exists(out)
with open(out, "a", newline="", encoding="utf-8-sig" if new_file else "utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
if new_file:
writer.writeheader()
for pair in filter(None, (p.strip() for p in routes.split(","))):
origin, _, destination = pair.partition("-")
try:
data = route(origin, destination)
except requests.RequestException as e: # e.g. a malformed code; go on to the next
print(f"{pair}: {e}")
continue
if data is None: # an unknown code, or no Skyscanner page for the pair
print(f"{pair}: no fares")
continue
for deal in data["deals"]:
leg = deal["legs"][0] # one leg on route pages: one-way quotes
writer.writerow({
"fetched_at": now.strftime("%Y-%m-%dT%H:%MZ"),
"origin": leg["origin"]["sky_code"],
"destination": leg["destination"]["sky_code"],
"date": leg["date"], "price": deal["price"], "currency": data["currency"],
"direct": deal["direct"], "carrier": leg.get("carrier_name"),
"quoted_at": leg["quoted_at"], "age_hours": age_hours(leg["quoted_at"], now),
"link": "https://www.skyscanner.net" + deal["deep_link_path"],
})
by_month = data.get("cheapest_by_month") or []
months = ", ".join(f"{m['month']} {m['price']}" for m in by_month)
print(f"{pair}: {len(data['deals'])} quotes, cheapest {data['cheapest_price']} "
f"{data['currency']}; by month: {months}")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('usage: python skyscanner_fares.py "lond-nyca,ber-bcn" [file.csv]')
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
python skyscanner_fares.py "lond-nyca,lhr-jfk,ber-bcn,syd-mel,del-dxb,mad-lis,sfo-tyoa" made 7 calls in 38 seconds and wrote 105 quotes, 13 to 16 per route. The two city codes widened the search: lond-nyca returned quotes from Gatwick, Heathrow, Luton and Stansted to both JFK and Newark, and sfo-tyoa covered Narita and Haneda.
How fresh the fares are
Treat the quotes as a guide, not a booking price. Of the 105, 48 had been quoted in the last 24 hours and the median age was 31.9 hours, but 28 were older than 4 days. The oldest, a £25 Madrid to Lisbon fare, was 12 days old. The script's age_hours column lets you drop stale ones.
Freshness varied by route. Quotes into JFK from the two London searches had a median age of 10 hours; Delhi to Dubai, 120 hours.
What it costs
Each route is one call and 1 credit, so seven routes once a day is about 210 credits a month. The 100 free credits a month cover the first two weeks; $19 buys 10,000 credits that never expire, and plans for higher volume cover more routes. Set your key and the first fare log is a CSV in under a minute.
For other prices pulled from public pages, see our Ozon price parser in Python and Zillow listings to CSV. For Airbnb listings and calendars, see does Airbnb have a public API.
We are not affiliated with Skyscanner.