{
  "markdown": "# Flywizz SDK\n\n[![PyPI version](https://img.shields.io/pypi/v/Flywizz.svg)](https://pypi.org/project/Flywizz/)\n[![Python versions](https://img.shields.io/pypi/pyversions/Flywizz.svg)](https://pypi.org/project/Flywizz/)\n[![CI](https://github.com/victorlane/flywizz/actions/workflows/ci.yml/badge.svg)](https://github.com/victorlane/flywizz/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/victorlane/flywizz/actions/workflows/codeql.yml/badge.svg)](https://github.com/victorlane/flywizz/actions/workflows/codeql.yml)\n[![PyPI downloads](https://img.shields.io/pypi/dm/Flywizz.svg)](https://pypi.org/project/Flywizz/)\n[![License](https://img.shields.io/github/license/victorlane/flywizz.svg)](https://github.com/victorlane/flywizz/blob/master/LICENSE)\n\nAn open-source unofficial API wrapper to get flight data from Wizz Air.\n\n<!-- mcp-name: io.github.victorlane/flywizz-mcp -->\n\n> [!TIP]\n> **MCP server for AI agents included.** Plug Flywizz into Claude Desktop,\n> Claude Code, or Cursor and search Wizz Air flights in natural language.\n> Jump to the [MCP Quickstart](#use-with-claude-cursor-and-other-mcp-clients).\n\n## Contents\n\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Three things to know first](#three-things-to-know-first)\n- [API Reference](#api-reference)\n- [Data Models](#data-models)\n- [Examples](#examples)\n- [Checking many routes at once](#checking-many-routes-at-once)\n- [Flights that need a connection](#flights-that-need-a-connection)\n- [Explore Mode](#explore-mode)\n- [**Use with Claude, Cursor, and other MCP clients**](#use-with-claude-cursor-and-other-mcp-clients)\n- [API characteristics](#api-characteristics)\n- [Caching](#caching)\n- [Rate Limiting](#rate-limiting)\n- [Contributing](#contributing)\n- [Disclaimer](#disclaimer)\n\n## Installation\n\n```bash\npip install Flywizz\n```\n\nOr using uv:\n\n```bash\nuv add Flywizz\n```\n\n## Quick Start\n\n```python\nfrom datetime import datetime, timedelta\nfrom flywizz import WizzAir, TimetableSearch\n\n# Initialize the client\nclient = WizzAir()\n\n# Set up search parameters\nsearch = TimetableSearch(\n    origin=\"BUD\",       # Budapest\n    destination=\"LTN\",  # London Luton\n    date_from=datetime.now() + timedelta(days=30),\n    date_to=datetime.now() + timedelta(days=60),\n)\n\n# One call gets the schedule and the prices\nfor day in client.get_timetable(search):\n    if day.price is None:\n        continue\n    print(f\"{day.departure_date.date()}: {day.price.amount} {day.price.currency}\")\n    print(f\"  departures: {', '.join(d.departure.strftime('%H:%M') for d in day.departures)}\")\n```\n\nEach entry is one operating day: the cheapest fare that day, plus every\ndeparture time, so a single call answers both \"when does it fly\" and \"what\ndoes it cost\".\n\n## Three things to know first\n\n### Prices are in the departure station's currency\n\nWizz Air has no server-side currency override. `BUD -> LTN` quotes in HUF,\n`LTN -> BUD` quotes in GBP, `WAW -> LTN` in PLN. Body fields, query params,\ncookies and headers named `currency` are all ignored.\n\nRead `Station.currency_code` from `get_network()` if you need to know which\ncurrency you'll get before you search, and convert client-side.\n\n### Not every operating day carries a price\n\n`timetableV2` and `farechart` attach a `price` object to every day, but on days\nthey will not quote inline, the `amount` is `0` and `price_type` is either\n`checkPrice` (a fare exists, but only through `search/search`) or `noData`.\nFlywizz maps both to `price=None`, so an unpriced day is never mistaken for a\nfree one. Timetable entries still expose the indicative fare through\n`original_price`:\n\n```python\nfor day in client.get_timetable(search):\n    if day.price is not None:\n        print(day.departure_date.date(), day.price.amount, day.price.currency)\n    elif day.original_price is not None:\n        print(day.departure_date.date(), \"~\", day.original_price.amount, \"(check price)\")\n```\n\n### Search windows are capped, and the caps differ\n\nPriced and unpriced surfaces disagree about how far ahead you may look. Both\nreject a wider window with `400 InvalidTimeDateRange` and no further\nexplanation, so Flywizz enforces each limit itself, in a message that names it.\n\n```python\nfrom flywizz.misc import (\n    MAX_TIMETABLE_WINDOW_DAYS,      # 42, for timetableV2 and farechart\n    MAX_FLIGHT_DATES_WINDOW_DAYS,   # 62, for the schedule endpoints\n)\n```\n\n`cheapest_weekend()` splits the range internally, since its default of\n`months_ahead=3` far exceeds either cap.\n\n### `search/search` is behind a bot gate\n\nFour endpoints (`search/search`, `booking/seatmap`, `booking/ancillaries`,\n`booking/passengers`) sit behind Kasada and answer `429` with an empty body\nfrom any non-browser client. Flywizz raises `BotGateError` rather than trying\nto solve the challenge.\n\nEverything else, including the priced `timetableV2` and `farechart` surfaces,\nis open. That is enough for price tracking, route exploration and calendar\nsearch. If you need fare bundles and sell keys, drive a real browser session\nand pass its headers in:\n\n```python\nfrom flywizz import WizzAir, WizzairTransport\n\nclient = WizzAir(WizzairTransport(kasada_headers={\n    \"x-kpsdk-ct\": \"...\",\n    \"x-kpsdk-v\": \"...\",\n    \"x-kpsdk-h\": \"...\",\n    \"x-kpsdk-cd\": \"...\",\n}))\n```\n\nFull details of the gate, the session handshake, and the whole route table are\nin [`docs/internal-api-spec.md`](docs/internal-api-spec.md).\n\n## API Reference\n\n### WizzAir Class\n\n#### Constructor\n\n```python\nWizzAir(transport: Optional[Transport] = None)\n```\n\nCreates a new Wizz Air client instance.\n\n**Parameters:**\n\n- `transport` (Transport, optional): Inject a custom transport, e.g. a\n  `CachingTransport` wrapping the default, a `WizzairTransport` with\n  `kasada_headers`, or a fixture transport for tests. Defaults to a fresh\n  `WizzairTransport`.\n\n**Example:**\n\n```python\n# Defaults\nclient = WizzAir()\n\n# With caching for the 650 KB network metadata\nfrom flywizz import CachingTransport, WizzairTransport\nclient = WizzAir(CachingTransport(WizzairTransport(), ttl=3600))\n```\n\n#### Methods\n\n| Method | Endpoint | What it gives you |\n|---|---|---|\n| `get_network(language=\"en-gb\")` | `asset/map` | Every station, its coordinates, currency, and connections |\n| `get_destinations(origin, direct_only=True)` | derived | Stations reachable from `origin` |\n| `explore_by_country(origin)` | derived | Destinations grouped by country code |\n| `validate_route(origin, destination)` | derived | Does Wizz Air fly this route direct |\n| `get_flight_dates(origin, destination, date_from, date_to)` | `search/flightDates` | Operating days, no prices, very cheap |\n| `get_flight_dates_multi(origin, destinations, date_from, date_to)` | `search/FlightDatesMultiArrival` | Operating days for up to 5 destinations per request, batched |\n| `get_connecting_flight_dates(origin, destination, date_from, date_to)` | `search/dohopFlightDates` | Operating days including one-stop connections |\n| `get_timetable(params)` | `search/timetableV2` | Cheapest fare per day, plus every departure |\n| `get_return_timetable(params)` | `search/timetableV2` | Outbound and inbound in one call |\n| `get_fare_chart(params)` | `asset/farechart` | Price strip around a target date |\n| `get_availability(params)` | `search/search` | Fare bundles and sell keys. **Bot-gated** |\n| `cheapest_in_month(origin, destination, month)` | derived | Cheapest day in a calendar month |\n| `cheapest_weekend(origin, destination, months_ahead=3)` | derived | Cheapest Fri-Sun or Fri-Mon return |\n| `explore_with_fares(origin, date_from, date_to, limit=None)` | derived | Every destination with its cheapest fare |\n| `get_flight_status(carrier_code, flight_number, date=None)` | `asset/flightinformation` | Live status for one flight number |\n| `get_currencies()` | `asset/currencies` | Supported ISO 4217 codes |\n| `get_countries()` | `asset/country` | Countries with EU / Schengen flags |\n| `get_cultures()` | `asset/cultures` | Site languages and their currencies |\n| `get_service_fees(currencies=None)` | `asset/serviceFees` | Published baggage, seat and change fees |\n| `get_wdc_prices()` | `asset/wdcPrice` | Discount Club tiers and minimum discounts |\n\nEvery method exists on `AsyncWizzAir` with the same signature.\n\n### TimetableSearch Class\n\nParameters for a timetable search.\n\n```python\nTimetableSearch(\n    origin: str,\n    destination: str,\n    date_from: datetime,\n    date_to: datetime,\n    return_date_from: Optional[datetime] = None,\n    return_date_to: Optional[datetime] = None,\n    adults: int = 1,\n    children: int = 0,\n    infants: int = 0,\n    price_type: str = \"regular\",\n)\n```\n\n**Parameters:**\n\n- `origin` (str): IATA code of the departure station (e.g. `\"BUD\"`)\n- `destination` (str): IATA code of the arrival station (e.g. `\"LTN\"`)\n- `date_from` (datetime): Start of the outbound departure window\n- `date_to` (datetime): End of the outbound departure window\n- `return_date_from` / `return_date_to` (datetime, optional): Inbound window.\n  Both are required by `get_return_timetable()`\n- `adults` / `children` / `infants` (int): Passenger counts. At least one adult\n- `price_type` (str): `\"regular\"` or `\"wdc\"` for Wizz Discount Club pricing\n\n### FareChartSearch Class\n\nParameters for the price strip.\n\n```python\nFareChartSearch(\n    origin: str,\n    destination: str,\n    date: datetime,\n    day_interval: int = 3,\n    adults: int = 1,\n    children: int = 0,\n    infants: int = 0,\n    price_type: str = \"regular\",\n)\n```\n\n`day_interval` is the half-window around `date` and must be at least 3, so the\ndefault returns seven days. Smaller values are rejected upstream with\n`DayIntervalMustBeGreaterOrEqualTo3`.\n\n### AvailabilitySearch Class\n\nParameters for the bot-gated availability call.\n\n```python\nAvailabilitySearch(\n    origin: str,\n    destination: str,\n    departure_date: datetime,\n    return_date: Optional[datetime] = None,\n    wdc: bool = True,\n    is_flight_change: bool = False,\n    adults: int = 1,\n    children: int = 0,\n    infants: int = 0,\n)\n```\n\n## Data Models\n\n### Price\n\nRepresents a money amount as Wizz Air reports it.\n\n**Attributes:**\n\n- `amount` (float): The amount\n- `currency` (str): ISO 4217 code, always the departure station's currency\n- `exchanged_amount` (Optional[float]): The SPA's client-side conversion hook.\n  Stays `None` for anonymous sessions\n- `exchanged_currency` (Optional[str]): Currency of `exchanged_amount`\n\n### TimetableEntry\n\nOne operating day for a route, with its cheapest fare.\n\n**Attributes:**\n\n- `departure_station` (str), `arrival_station` (str): IATA codes\n- `departure_date` (datetime): The operating day\n- `price` (Optional[Price]): Cheapest fare that day, `None` if sold out\n- `original_price` (Optional[Price]): Pre-discount price\n- `departures` (list[Departure]): Every departure that day\n- `price_type` (Optional[str]): `\"price\"` when there was inventory\n- `has_mac_flight` (bool): The route includes a metropolitan-area alternative\n- `applied_coupon_code` (Optional[str])\n\n### Departure\n\n**Attributes:**\n\n- `departure` (datetime): Departure time\n- `is_cheapest_of_the_day` (bool): This is the departure `price` refers to\n\n### FlightDate\n\nOne operating day from `get_connecting_flight_dates()`.\n\n**Attributes:**\n\n- `date` (datetime): The operating day\n- `stops` (int): 0 for a direct flight, 1 or more for a connection\n- `is_direct` (bool): Property, true when `stops` is 0\n\n### FareChartEntry\n\nOne day of the price strip.\n\n**Attributes:**\n\n- `departure_station` (str), `arrival_station` (str): IATA codes\n- `day` (datetime): The day\n- `price` (Optional[Price]): Cheapest price that day\n- `class_of_service` (Optional[str]): Booking class the quote came from\n- `price_type` (Optional[str]), `has_mac_flight` (bool)\n\n### Station\n\nAn airport in Wizz Air's live network. Returned by the explore methods.\n\n**Attributes:**\n\n- `iata` (str): IATA station code\n- `name` (str): Station name\n- `country_code` (str): **Uppercase** ISO2 country code (e.g. `\"HU\"`, `\"GB\"`)\n- `country_name` (str): Country name\n- `currency_code` (str): Local currency. Fares from here are priced in it\n- `latitude` (float), `longitude` (float): Coordinates\n- `mac` (Optional[str]): Metropolitan area code (e.g. `\"LON\"`)\n- `aliases` (list[str]): Alternative names\n- `categories` (list[int]): Marketing categories assigned by Wizz Air\n- `rank` (Optional[int]), `is_fake_station` (bool)\n- `connections` (list[Connection]): Everywhere this station flies\n\nHelper: `destinations(direct_only=True)` returns just the IATA codes.\n\n### Connection\n\n**Attributes:**\n\n- `iata` (str): Destination station code\n- `is_direct` (bool): A direct Wizz Air flight. The flag you usually want\n- `is_connected` (bool): A self-transfer connection rather than a direct flight\n- `is_domestic` (bool), `is_new` (bool)\n- `operation_start_date` (Optional[datetime]): When the route opens\n\n### FlightStatus\n\nA single operating flight from the flight-information endpoint.\n\n**Attributes:**\n\n- `flight_id` (int), `carrier_code` (str), `flight_number` (int)\n- `departure_airport` (str), `arrival_airport` (str)\n- `original_departure_airport` / `original_arrival_airport` (Optional[str]):\n  Differ from the actual airports when the flight was diverted\n- `operation_day` (Optional[datetime])\n- `scheduled_departure` / `scheduled_arrival` (Optional[datetime])\n- `op_suffix` (Optional[str])\n\n### DestinationFare\n\nReturned by `explore_with_fares()`. Pairs a reachable destination with its\ncheapest sampled fare, if one came back from the price probe.\n\n**Attributes:**\n\n- `station` (Station): The destination\n- `price` (Optional[Price]): Cheapest fare in the window, or `None` if the\n  route is in the network but no priced inventory came back\n- `departure_date` (Optional[datetime]): The day that fare was on\n\n## Examples\n\n### Cheapest day in a month\n\n```python\nfrom datetime import datetime\nfrom flywizz import WizzAir\n\nclient = WizzAir()\ncheapest = client.cheapest_in_month(\"BUD\", \"LTN\", datetime(2026, 11, 1))\n\nif cheapest:\n    print(f\"{cheapest.departure_date.date()}: \"\n          f\"{cheapest.price.amount} {cheapest.price.currency}\")\n```\n\n### Is it cheaper a day either side?\n\n```python\nfrom datetime import datetime\nfrom flywizz import WizzAir, FareChartSearch\n\nclient = WizzAir()\nstrip = client.get_fare_chart(\n    FareChartSearch(origin=\"BUD\", destination=\"LTN\",\n                    date=datetime(2026, 11, 10), day_interval=3)\n)\n\nfor day in strip:\n    price = f\"{day.price.amount:.0f} {day.price.currency}\" if day.price else \"-\"\n    print(f\"{day.day.date()}  {price}\")\n```\n\n### Cheapest weekend in the next three months\n\n```python\nfrom flywizz import WizzAir\n\nclient = WizzAir()\nweekend = client.cheapest_weekend(\"BUD\", \"LTN\", months_ahead=3)\n\nif weekend:\n    out, back = weekend\n    total = out.price.amount + back.price.amount\n    print(f\"{out.departure_date.date()} -> {back.departure_date.date()}: \"\n          f\"{total} {out.price.currency}\")\n```\n\n### Discount Club pricing\n\n```python\nfrom datetime import datetime, timedelta\nfrom flywizz import WizzAir, TimetableSearch\n\nclient = WizzAir()\nwdc = client.get_timetable(\n    TimetableSearch(\n        origin=\"BUD\", destination=\"LTN\",\n        date_from=datetime.now() + timedelta(days=30),\n        date_to=datetime.now() + timedelta(days=45),\n        price_type=\"wdc\",\n    )\n)\n```\n\n### Live flight status\n\n```python\nfrom flywizz import WizzAir\n\nclient = WizzAir()\nfor leg in client.get_flight_status(\"W6\", \"6201\"):\n    print(f\"{leg.operation_day.date()} {leg.departure_airport} -> {leg.arrival_airport}\")\n```\n\nCarrier codes are the AOC prefix: `W6` (Hungary), `W4` (Malta), `W9` (UK).\n\n### Error Handling\n\n```python\nfrom flywizz import BotGateError, ValidationError, WizzairException\n\ntry:\n    entries = client.get_timetable(search)\n    if not entries:\n        print(\"No flights found for the given criteria\")\nexcept ValidationError as e:\n    print(f\"Wizz Air rejected the request: {e.codes}\")\nexcept BotGateError:\n    print(\"This endpoint needs a browser session\")\nexcept WizzairException as e:\n    print(f\"Wizz Air API error: {e}\")\n```\n\n`ValidationError.codes` carries Wizz Air's own validation codes, which name\nthe fields it objected to. An empty list means the API answered with nothing\nmatching; it never means a failure.\n\n## Checking many routes at once\n\n`get_flight_dates_multi()` answers the schedule question for several\ndestinations per request, which is five times cheaper than looping over\n`get_flight_dates()`:\n\n```python\nfrom datetime import datetime, timedelta\nfrom flywizz import WizzAir, WizzairTransport, CachingTransport\n\nclient = WizzAir(CachingTransport(WizzairTransport()))\nstart = datetime.now() + timedelta(days=30)\n\ndestinations = [s.iata for s in client.get_destinations(\"BUD\")]\ndates = client.get_flight_dates_multi(\"BUD\", destinations, start, start + timedelta(days=30))\n\nfor iata, days in dates.items():\n    print(f\"{iata}: {len(days)} operating days\")\n```\n\nEvery destination you ask for appears in the result. A route that does not\noperate in the window maps to an empty list rather than going missing, so\nthere is no membership check to forget.\n\nThe endpoint answers for at most five destinations per request and reports an\nover-long list by returning *nothing* rather than an error. Flywizz batches\nfor you, so the list you pass has no practical ceiling.\n\nFares are a different matter: there is no batched priced surface, so\n`explore_with_fares()` still costs one call per destination.\n\n## Flights that need a connection\n\n`validate_route()` and `get_flight_dates()` cover direct service only, so a\n`False` from either does not mean you cannot fly the route.\n`get_connecting_flight_dates()` also answers for pairs that need a change of\nplane:\n\n```python\nfrom datetime import datetime, timedelta\nfrom flywizz import WizzAir\n\nclient = WizzAir()\nstart = datetime.now() + timedelta(days=30)\n\nclient.validate_route(\"KTW\", \"LIS\")   # False - no direct flight\n\nfor day in client.get_connecting_flight_dates(\"KTW\", \"LIS\", start, start + timedelta(days=30)):\n    print(day.date.date(), \"direct\" if day.is_direct else f\"{day.stops} stop(s)\")\n```\n\nOn a route that flies direct only some days, both kinds come back interleaved,\nso you can see which days need a connection. Filter on `is_direct` when one\nwill not do.\n\n## Explore Mode\n\nExplore Mode answers the question \"where can I actually fly from here?\". It\nreads Wizz Air's live network metadata once and exposes the reachable\ndestinations from any station, optionally grouped or joined with the cheapest\nfare in a date window.\n\nAll methods below are available on both `WizzAir` and `AsyncWizzAir`.\n\n### List every destination\n\n```python\nfor station in client.get_destinations(\"BUD\"):\n    print(f\"{station.iata} {station.name} ({station.country_code})\")\n```\n\nPass `direct_only=False` to include self-transfer connections.\n\n### Group destinations\n\n```python\nby_country = client.explore_by_country(\"BUD\")\n\nprint(f\"BUD flies to {len(by_country)} countries\")\nfor country, stations in sorted(by_country.items()):\n    codes = \", \".join(s.iata for s in stations)\n    print(f\"  {country}: {codes}\")\n```\n\nCountry codes are **uppercase** ISO2.\n\n### Check a single route\n\n```python\nclient.validate_route(\"BUD\", \"LTN\")  # True\n```\n\n### Destinations with their cheapest fare\n\n`explore_with_fares()` joins the network destinations with a timetable probe,\nso each destination comes back with its cheapest `Price` (or `None` if no\ninventory was returned for that route in the window).\n\nWizz Air has no \"anywhere\" search, so this is one call per destination. Use\n`limit` while iterating and wrap the transport in `CachingTransport`.\n\n```python\nfrom datetime import datetime, timedelta\n\nstart = datetime.now() + timedelta(days=30)\nend = start + timedelta(days=14)\n\nresults = client.explore_with_fares(\"BUD\", start, end, limit=20)\n\npriced = [d for d in results if d.price is not None]\nfor d in sorted(priced, key=lambda d: d.price.amount)[:10]:\n    print(f\"{d.station.iata} {d.station.name}: \"\n          f\"{d.price.amount} {d.price.currency}\")\n```\n\nPrices across destinations are all in the **origin's** currency, so they are\ndirectly comparable.\n\n### Async usage\n\n`AsyncWizzAir` mirrors every explore method, and `explore_with_fares()` fans\nout concurrently:\n\n```python\nimport asyncio\nfrom datetime import datetime, timedelta\nfrom flywizz import AsyncWizzAir\n\nasync def main():\n    async with AsyncWizzAir() as client:\n        results = await client.explore_with_fares(\n            \"BUD\",\n            datetime.now() + timedelta(days=30),\n            datetime.now() + timedelta(days=45),\n            limit=20,\n            concurrency=5,\n        )\n        print(f\"{sum(1 for r in results if r.price)} priced destinations\")\n\nasyncio.run(main())\n```\n\nIf you call multiple explore methods in a row, wrap the transport in\n`CachingTransport` so the network metadata is fetched once and reused.\n\n## Use with Claude, Cursor, and other MCP clients\n\n> [!IMPORTANT]\n> Two commands and you're done:\n>\n> ```bash\n> uv tool install \"Flywizz[mcp]\"\n> claude mcp add flywizz flywizz-mcp\n> ```\n>\n> Now your agent can search Wizz Air flights in natural language. No API\n> keys, no accounts.\n\nFlywizz ships an optional Model Context Protocol server so your agent can\nsearch Wizz Air fares from natural-language prompts like *\"what's the cheapest\nday in November to fly Budapest to London\"* or *\"where can I fly from Budapest\nin the first week of December\"*.\n\n### Quickstart\n\n**1. Install Flywizz with the MCP extra:**\n\n```bash\nuv tool install \"Flywizz[mcp]\"\n```\n\nOr with pip:\n\n```bash\npipx install \"Flywizz[mcp]\"\n```\n\nThis installs a `flywizz-mcp` console script on your PATH.\n\n**2. Add it to your agent:**\n\n**Claude Code** (one-liner):\n\n```bash\nclaude mcp add flywizz flywizz-mcp\n```\n\n**Claude Desktop**: open `~/Library/Application Support/Claude/claude_desktop_config.json`\non macOS (or `%APPDATA%\\Claude\\claude_desktop_config.json` on Windows) and add:\n\n```json\n{\n  \"mcpServers\": {\n    \"flywizz\": {\n      \"command\": \"flywizz-mcp\"\n    }\n  }\n}\n```\n\nThen restart Claude Desktop.\n\n**Cursor**: Settings → MCP → Add new server, name `flywizz`, command\n`flywizz-mcp`.\n\n**3. Try it.** Ask your agent:\n\n> \"What's the cheapest day in November to fly from Budapest to London Luton?\"\n\nThe agent should call `cheapest_day` with `origin=\"BUD\"`,\n`destination=\"LTN\"`, `month=\"2026-11-01\"`, then report the day and the price.\n\n### Currency\n\nThere is no currency setting, because Wizz Air has none. Every tool returns\nprices in the departure station's local currency and reports the code\nalongside the amount. Tell your agent to quote the currency it gets back\nrather than assuming euros.\n\n### Exposed tools\n\nThe server exposes five curated tools so the agent can pick reliably:\n\n- `find_fares` for \"how much is BUD to LTN in November\", with the full\n  day-by-day breakdown and every departure time\n- `cheapest_day` for \"what's the cheapest day this month to fly X to Y\"\n- `price_around` for \"is it cheaper a day either side of the 10th\"\n- `explore_destinations` for \"what countries can I reach from X\"\n- `flight_status` for \"when does W6 6201 operate\"\n\nNo API keys, accounts, or rate-limit setup. The server reuses a single cached\n`WizzAir` client across calls, so the network metadata is fetched once per\nprocess.\n\nThe bot-gated `search/search` surface is deliberately not exposed: it cannot\nwork from a headless process, and an agent tool that always fails is worse\nthan no tool.\n\n## API characteristics\n\nThese properties of the upstream API determine what this SDK can and cannot\noffer. Flywizz handles each of them for you; knowing them explains why some\ncalls behave the way they do.\n\n| | Behaviour |\n|---|---|\n| Country codes | Uppercase ISO 3166-1 alpha-2. Lowercase codes are rejected. |\n| Authentication | Anonymous, but every request needs a session handshake and a CSRF token that rotates between calls. |\n| Currency | Determined by the departure station and not negotiable. Convert client-side. |\n| Cheap-fare search | There is no \"anywhere\" endpoint. `explore_with_fares()` fans out one call per destination. |\n| Priced surfaces | `timetableV2` and `farechart` are open; `search/search` is gated. |\n| Pagination | None. Every response is complete, which is why `asset/map` is 650 KB. |\n| Window limits | A timetable window may span at most 42 days; a schedule window, 62. |\n| Bot protection | Kasada, permanently, on four endpoints. |\n\n## Caching\n\n`asset/map` is 650 KB and changes rarely. Wrap the transport when you call it\nmore than once:\n\n```python\nfrom flywizz import WizzAir, WizzairTransport, CachingTransport\n\nclient = WizzAir(CachingTransport(WizzairTransport(), ttl=3600))\n```\n\nAsynchronous code requires the asynchronous wrapper. The two are not\ninterchangeable: mixing them raises `TypeError` rather than caching a\ncoroutine.\n\n```python\nfrom flywizz import AsyncWizzAir, AsyncWizzairTransport, AsyncCachingTransport\n\nclient = AsyncWizzAir(AsyncCachingTransport(AsyncWizzairTransport(), ttl=3600))\n```\n\nNeither wrapper caches POSTs, so fares stay live. Call `invalidate()` to drop\nthe cache early.\n\n## Rate Limiting\n\nThe SDK retries network errors and 5xx responses with exponential backoff, up\nto 4 attempts. It deliberately does **not** retry a `429`: on this API that is\nthe Kasada bot gate rather than backpressure, and retrying just adds load\nwhile still failing.\n\nWizz Air's API is anonymous, but it is not yours. Be a good citizen: cache the\nnetwork metadata, keep `explore_with_fares()` fan-out modest, and don't poll\nfares faster than the prices actually change.\n\n## Contributing\n\nThis is an open-source project. Contributions are welcome — see\n[CONTRIBUTING.md](CONTRIBUTING.md). Agent-facing notes on the architecture\nlive in [AGENTS.md](AGENTS.md), and everything known about the upstream API is\nin [docs/internal-api-spec.md](docs/internal-api-spec.md).\n\n## Disclaimer\n\nThis is an unofficial API wrapper and is not affiliated with Wizz Air. It\nperforms read-only requests against the public endpoints the airline's own\nwebsite uses. Use at your own risk and ensure you comply with Wizz Air's terms\nof service.\n",
  "bytes": 26027,
  "sha": "4586366904946c8045e8a6951d19026a83d36d2daab65578eb0316c629bf1226",
  "repo_slug": "victorlane/flywizz",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_victorlane_flywizz_mcp_681c57dc/readme"
}