Sign inTry it

Find the cheapest Ryanair flight on a route, day by day.

Ryanair's fare finder for one route: for every day in a date range (up to two calendar months), the cheapest one-way fare for one adult with its departure and arrival time, in the currency you choose. Add a return range to get the way back too. Days without a flight or sold out are left out. Each flight links to Ryanair's flight selection for that day, where seats, bags and the final price are shown and booked.

No reports yetRead-only, no login
Site
Ryanair, Ireland
Version
v1
Runs, last 7 days
No reports yet
sha256
f6c061d7bba5…

Run it with your agent

after installing Wield

Ask in plain words. Your agent finds this recipe and calls it:

“Find the cheapest Ryanair flight on a route, day by day.”

Read-only: it changes nothing on the site. No login needed.

{
  "tool": "run",
  "arguments": {
    "recipe_id": "ryanair.com/search-flights",
    "params": {
      "date_from": "2027-01-11",
      "date_to": "2027-01-17",
      "destination": "BCN",
      "origin": "BER"
    }
  }
}

Requests

sent from your browser, in order
  1. 1GET/api/farfnd/v4/oneWayFares/{{f.from}}/{{f.to}}/cheapestPerDay?currency&outboundMonthOfDateThe fare finder's cheapest-per-day API, once per leg and calendar month (at most 4 requests). The one-item-per-call list says which leg and month each call is for.repeats, max 4

Parameters

from your agent
currencyenum "EUR" | "GBP" | "PLN" | "HUF" | "CZK" | "SEK" | "NOK" | "DKK" | "CHF" | "MAD" | "RON" | "BGN" = "EUR"
date_fromstringrequiredFirst departure day, YYYY-MM-DD
date_tostringLast departure day, YYYY-MM-DD (default: date_from). Same or next calendar month as date_from
destinationstringrequiredArrival airport IATA code, e.g. 'BCN' (Barcelona), 'BGY' (Milan Bergamo)
max_pricenumberLeave out days whose cheapest fare is higher, in the chosen currency
originstringrequiredDeparture airport IATA code, e.g. 'BER' (Berlin), 'STN' (London Stansted), 'DUB' (Dublin)
return_fromstringFirst day for the way back (destination → origin), YYYY-MM-DD. Leave out for one way
return_tostringLast day for the way back (default: return_from). Same or next calendar month as return_from

Returns

to your agent
cheapest_outboundobject
cheapest_returnobject
currencystring
destinationstring
originstring
outboundarray
returnarrayEmpty for one way

Where it can send

  • www.ryanair.com

Anything else is blocked by the extension.

Reads from your session

Nothing. Your browser attaches the site's cookies by itself.

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • length(output.outbound) > `2`
  • length(output.outbound) <= `7`
  • length(output.outbound[?starts_with(date, '2027-01-1')]) == length(output.outbound)
  • output.cheapest_outbound.price > `0`
  • length(output.outbound[?currency == 'EUR' && price > `0` && starts_with(url, 'https://www.ryanair.com/')]) == length(output.outbound)
  • length(output.return) == `0`

Raw recipe

Served as canonical JSON from /api/v1/recipes/ryanair.com/search-flights, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/ryanair.com/search-flights | shasum -a 256
# f6c061d7bba54d752ac0bc6bc81e05f129d499bdb10c8b4522d2d8e95f3e70b5
ryanair.com/search-flights.json, v1
{
  "description": "Ryanair's fare finder for one route: for every day in a date range (up to two calendar months), the cheapest one-way fare for one adult with its departure and arrival time, in the currency you choose. Add a return range to get the way back too. Days without a flight or sold out are left out. Each flight links to Ryanair's flight selection for that day, where seats, bags and the final price are shown and booked.",
  "effect": "read",
  "id": "ryanair.com/search-flights",
  "keywords": [
    "ryanair",
    "flights",
    "cheap flights",
    "low cost",
    "fare finder",
    "one way",
    "return",
    "flug",
    "flüge",
    "billigflug",
    "günstig fliegen",
    "vuelos baratos",
    "voli low cost",
    "lot",
    "airline",
    "airport",
    "iata"
  ],
  "output": {
    "schema": {
      "$defs": {
        "flight": {
          "properties": {
            "arrival": {
              "description": "Local time at the arrival airport",
              "type": "string"
            },
            "currency": {
              "type": "string"
            },
            "date": {
              "description": "Departure day, YYYY-MM-DD",
              "type": "string"
            },
            "departure": {
              "description": "Local time at the departure airport, YYYY-MM-DDTHH:MM:SS",
              "type": "string"
            },
            "from": {
              "type": "string"
            },
            "price": {
              "description": "Cheapest fare that day for one adult, before bags and seats",
              "type": "number"
            },
            "to": {
              "type": "string"
            },
            "url": {
              "description": "Ryanair's flight selection for that day",
              "type": "string"
            }
          },
          "type": "object"
        }
      },
      "properties": {
        "cheapest_outbound": {
          "type": [
            "object",
            "null"
          ]
        },
        "cheapest_return": {
          "type": [
            "object",
            "null"
          ]
        },
        "currency": {
          "type": "string"
        },
        "destination": {
          "type": "string"
        },
        "origin": {
          "type": "string"
        },
        "outbound": {
          "items": {
            "$ref": "#/$defs/flight"
          },
          "type": "array"
        },
        "return": {
          "description": "Empty for one way",
          "items": {
            "$ref": "#/$defs/flight"
          },
          "type": "array"
        }
      },
      "required": [
        "origin",
        "destination",
        "currency",
        "outbound",
        "return"
      ],
      "type": "object"
    },
    "value": "let $cur = params.currency || 'EUR', $max = params.max_price, $olo = to_number(join('', split(params.date_from, '-'))), $ohi = to_number(join('', split(params.date_to || params.date_from, '-'))), $rlo = params.return_from && to_number(join('', split(params.return_from, '-'))), $rhi = params.return_from && to_number(join('', split(params.return_to || params.return_from, '-'))) in let $all = map(&(let $c = @ in map(&(let $x = @ in {leg: $c.f.leg, n: to_number(join('', split($x.day, '-'))), date: $x.day, from: $c.f.from, to: $c.f.to, departure: $x.departureDate, arrival: $x.arrivalDate, price: $x.price.value, currency: $x.price.currencyCode || $cur, url: join('', ['https://www.ryanair.com/gb/en/trip/flights/select?adults=1&teens=0&children=0&infants=0&dateOut=', $x.day, '&isConnectedFlight=false&isReturn=false&discount=0&originIata=', $c.f.from, '&destinationIata=', $c.f.to])}), $c.fares[?price != `null` && !soldOut && !unavailable] || `[]`)), steps.fares || `[]`)[] in let $out = sort_by($all[?leg == 'outbound' && n >= $olo && n <= $ohi && ($max == `null` || price <= $max)], &n)[*].{date: date, from: from, to: to, departure: departure, arrival: arrival, price: price, currency: currency, url: url}, $ret = sort_by($all[?leg == 'return' && $rlo != `null` && n >= $rlo && n <= $rhi && ($max == `null` || price <= $max)], &n)[*].{date: date, from: from, to: to, departure: departure, arrival: arrival, price: price, currency: currency, url: url} in {origin: upper(params.origin), destination: upper(params.destination), currency: $cur, outbound: $out, return: $ret, cheapest_outbound: min_by($out, &price) || `null`, cheapest_return: min_by($ret, &price) || `null`}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "currency": {
        "default": "EUR",
        "enum": [
          "EUR",
          "GBP",
          "PLN",
          "HUF",
          "CZK",
          "SEK",
          "NOK",
          "DKK",
          "CHF",
          "MAD",
          "RON",
          "BGN"
        ],
        "type": "string"
      },
      "date_from": {
        "description": "First departure day, YYYY-MM-DD",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "type": "string"
      },
      "date_to": {
        "description": "Last departure day, YYYY-MM-DD (default: date_from). Same or next calendar month as date_from",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "type": "string"
      },
      "destination": {
        "description": "Arrival airport IATA code, e.g. 'BCN' (Barcelona), 'BGY' (Milan Bergamo)",
        "pattern": "^[A-Za-z]{3}$",
        "type": "string"
      },
      "max_price": {
        "description": "Leave out days whose cheapest fare is higher, in the chosen currency",
        "minimum": 0,
        "type": "number"
      },
      "origin": {
        "description": "Departure airport IATA code, e.g. 'BER' (Berlin), 'STN' (London Stansted), 'DUB' (Dublin)",
        "pattern": "^[A-Za-z]{3}$",
        "type": "string"
      },
      "return_from": {
        "description": "First day for the way back (destination → origin), YYYY-MM-DD. Leave out for one way",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "type": "string"
      },
      "return_to": {
        "description": "Last day for the way back (default: return_from). Same or next calendar month as return_from",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "type": "string"
      }
    },
    "required": [
      "origin",
      "destination",
      "date_from"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "Ryanair's fare finder pages call /api/farfnd/v4/oneWayFares/<from>/<to>/cheapestPerDay?outboundMonthOfDate=<YYYY-MM-01>&currency=<code>: one entry per day of that month with the cheapest one-way fare, departure and arrival (local times, no offset), soldOut and unavailable flags. currency converts (STN→DUB in EUR works). The booking availability API (/api/booking/v4/<market>/availability) answers servers and cookie-less clients with 409 'Availability declined', so this recipe uses the fare finder only: prices are for one adult before bags, seats and fees, and the link opens Ryanair's own flight selection. Dates are compared as numbers (JMESPath here compares numbers, not strings). Answers servers.",
    "recorded_at": "2026-11-07T21:32:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "IE",
    "id": "ryanair.com",
    "language": "en",
    "name": "Ryanair",
    "origin": "https://www.ryanair.com",
    "origins": [
      "https://www.ryanair.com"
    ]
  },
  "steps": [
    {
      "description": "The fare finder's cheapest-per-day API, once per leg and calendar month (at most 4 requests). The one-item-per-call list says which leg and month each call is for.",
      "expect": {
        "assert": "body.outbound.fares != `null`",
        "content_type": "json",
        "status": [
          200
        ]
      },
      "extract": {
        "json": {
          "fares": "outbound.fares"
        }
      },
      "foreach": {
        "as": "f",
        "in": "let $o = upper(params.origin), $d = upper(params.destination), $to = params.date_to || params.date_from, $rf = params.return_from, $rt = params.return_to || params.return_from in [{leg: 'outbound', from: $o, to: $d, month: join('', [params.date_from[0:7], '-01'])}, {leg: 'outbound', from: $o, to: $d, month: ($to[0:7] != params.date_from[0:7]) && join('', [$to[0:7], '-01']) || `null`}, {leg: 'return', from: $d, to: $o, month: $rf && join('', [$rf[0:7], '-01']) || `null`}, {leg: 'return', from: $d, to: $o, month: ($rf && $rt[0:7] != $rf[0:7]) && join('', [$rt[0:7], '-01']) || `null`}][?month]",
        "max": 4
      },
      "id": "fares",
      "request": {
        "headers": {
          "Accept": "application/json"
        },
        "method": "GET",
        "query": {
          "currency": "{{params.currency}}",
          "outboundMonthOfDate": "{{f.month}}"
        },
        "url": "/api/farfnd/v4/oneWayFares/{{f.from}}/{{f.to}}/cheapestPerDay"
      }
    }
  ],
  "task": "Find the cheapest Ryanair flight on a route, day by day",
  "tos": {
    "notes": "Ryanair's website terms allow private, non-commercial use and forbid automated extraction for commercial purposes (screen scraping). This recipe is for one person's own search: 1–4 requests, the same ones the fare finder makes. robots.txt disallows /api for crawlers. Booking stays on ryanair.com.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.outbound) > `2`",
      "length(output.outbound) <= `7`",
      "length(output.outbound[?starts_with(date, '2027-01-1')]) == length(output.outbound)",
      "output.cheapest_outbound.price > `0`",
      "length(output.outbound[?currency == 'EUR' && price > `0` && starts_with(url, 'https://www.ryanair.com/')]) == length(output.outbound)",
      "length(output.return) == `0`"
    ],
    "example_params": {
      "date_from": "2027-01-11",
      "date_to": "2027-01-17",
      "destination": "BCN",
      "origin": "BER"
    },
    "max_ms": 4000
  },
  "version": 1
}