In my previous post I talked about a layover finder tool. Basically a tool that let’s you find cheaper flights by finding a city to have a multiple day layover in.

Now I will try to actually build it. It shouldn’t be that hard right?

After doing just a little bit of research, I decided to use the Amadeus api. Why? Because you need to register as a partner to use the skyscanner api, and I’m too lazy to scrape google flights manually.

They offer a bunch of different endpoints, and I have to figure out which one I can use. Here is that might be relevant:

  1. Flight inspiration search: “Where are the cheapest places to fly from Boston?”, nice but not directly usable. Maybe I can use it in the future, when I am looking to get a quote for all possible cities.
  2. Flight offers search: “What are the cheapest flights from Madrid to Paris on June 1st?”, It is usable, but ideally it would return something like “The cheapest flight prices for each day between x and y”
  3. Flight cheapest day search: “What are the cheapest dates to fly from Munich to Sao Paulo?”, This might be it, depending on how the response looks. They have the openapi spec on their site but it hangs every time I try to open it, so I downloaded the json, let’s see.

The request takes the following params:

  • origin
  • destination
  • departureDate: the date, or range of dates, on which the flight will depart from the origin. Dates are specified in the ISO 8601 YYYY-MM-DD format, e.g. 2017-12-25. Ranges are specified with a comma and are inclusive
  • oneWay
  • duration: Only necessary if it is a round trip
  • nonStop
  • maxPrice
  • viewBy: view the flight dates by DATE, DURATION, or WEEK. View by DATE (default when oneWay is true) to get the cheapest flight dates for every departure date in the given range. View by DURATION (default when oneWay is false) to get the cheapest flight dates for every departure date and for every duration in the given ranges. View by WEEK to get the cheapest flight destination for every week in the given range of departure dates. Note that specifying a detailed view but large ranges may result in a huge number of flight dates being returned. For some very large numbers of flight dates, the API may refuse to provide a response

The description for the viewBy field tells me this is the endpoint I should use.

And the response is a list of prices for each date.

Looking for flights from Berlin to London, the response is a list of dates with the lowest price. Something like the following.

{
data: [
    ...
    {
        "type": "flight-date",
        "origin": "BER",
        "destination": "LON",
        "departureDate": "2025-12-01",
        "returnDate": "",
        "price": {"total": "140.84"},
        "links": {"flightDestinations": "https://test.api.amadeus.com/v1/shopping/flight-destinations?origin=BER&departureDate=2025-12-01,2025-12-15&oneWay=true&nonStop=true&maxPrice=500&viewBy=DURATION",
        "flightOffers": "https://test.api.amadeus.com/v2/shopping/flight-offers?originLocationCode=BER&desinationLocationCode=LON&departureDate=2025-12-01&adults=1&nonStop=true&maxPrice=500&viewBy=DURATION"}
    }
    ...
    ]
}

So now that we can get the lowest price per day between two cities, I need to find the prices to and from a bunch of cities and compare the minimum prices. But I don’t want to just hammer the API looking for ALL of the cities. Let me just start with a few airports to test our algorithm. To look up the cities I need their IATA codes. For Berlin the airport code is BER, and Ho Chi Minh City has two international airports, SGN and LTH. Although when looking up flights it was mostly SGN. Let me hand pick some cities from the map to run it. I’ll try to hubs that are kinda close and between Berlin and Ho Chi Minh City. I’m looking at london, IsLondon, Istanbul, Dubai, Abu Dhabi, Mumbai, Singapore, Hong Kongtanbul, Dubai, Abu Dhabi, Mumbai, Singapore, Hong Kong. I think this is enough for a test.

This function should take in source, destination, hops, maximum delay in days, date from, date to, and should give us a list of prices for each hop, date, and delay.

Amadeus provides a testing environment with limited data to use during development. Looks like they don’t have data for all airports there. It only has London, Berlin, and Istanbul, from the ones I tested. Mayve it has more european airports? Let me try some european airports. Let’s go Berlin to Istanbul, using London, Paris, Rome, Barcelona, Athens.

Looks like the test data is really patchy, most of the time one leg has a connection but the other one doesn’t. Let’s see if I can access to production.

Somehow it says my authentication credentials are wrong, also it says that the api is going to be decomissioned soon. Maybe it is already decomissioned? Looks like people on stack overflow are saying you need to wait until the prod credentials actually propagate or something?

After a while the API just started working, but it doesn’t even find flights for most routes. I guess I will need to scrape some other provider. There are some candidates

  • Google flights: pretty good but hard to reverse engineer their API I think, they use protobuf for the requests.
  • Kayak: their api looks good, tried scraping it, but the aggregated date data is more expensive than the cheapest price on that day, maybe they are not keeping it up to date enough?
  • Trip.com: They are actually pretty good at finding weird connections, but some dates are just missing. Maybe they just cache the days people have looked into before?
  • Skyscanner: The prices are up to date and pretty good. Sometimes they have prices for 3 leg 30 hour flights, which kinda defeats the purpose of a tool like this I guess.

In the end I tested Amadeus, Kayak, Trip.com, and Skyscanner. I think Skyscanner works the best. The function now looks like this

prices = find_layover_prices(
    client,
    "BER",
    "SGN",
    set(["IST", "DXB", "AUH", "BOM", "SIN", "HKG", "KWI", "DOH", "FRA", "BUD", "PEK",
     'ATL', 'DXB', 'DFW', 'HND', 'LHR', 'DEN', 'IST', 'ORD', 'DEL', 'PVG',
    'LAX', 'CAN', 'ICN', 'CDG', 'SIN', 'PEK', 'AMS', 'MAD', 'JFK', 'SZX',
    'BKK', 'FRA', 'CLT', 'LAS', 'MCO', 'KUL', 'MIA', 'BCN', 'TFU', 'CGK',
    'BOM', 'HKG', 'DOH', 'SEA', 'PHX', 'SFO', 'MNL', 'PKX', 'FCO', 'JED',
    'EWR', 'CKG', 'IAH', 'HGH', 'SHA', 'KMG', 'XIY', 'YYZ', 'BOG', 'MEX'
     ]),
    "2025-11-15",
    "2025-12-31",
    longest_layover_days=3
)

Kinda ugly, but I just updated the list with a list from busiest airports wikipedia, that’s why. And the results now look like this.

1. Via BOM - Total: €259.11
   BER-BOM: €176.99 (low) - departs 2025-11-17
   BOM-SGN: €82.12 (low) - departs 2025-11-19
   Layover: 2 days

2. Via KWI - Total: €261.98
   BER-KWI: €111.99 (medium) - departs 2025-11-23
   KWI-SGN: €149.99 (low) - departs 2025-11-24
   Layover: 1 days

3. Via BOM - Total: €264.99
   BER-BOM: €165.99 (low) - departs 2025-11-25
   BOM-SGN: €99.00 (low) - departs 2025-11-26
   Layover: 1 days

4. Via DEL - Total: €266.44
   BER-DEL: €154.99 (low) - departs 2025-11-18
   DEL-SGN: €111.45 (medium) - departs 2025-11-19
   Layover: 1 days

5. Via DEL - Total: €266.44
   BER-DEL: €154.99 (low) - departs 2025-11-18
   DEL-SGN: €111.45 (medium) - departs 2025-11-20
   Layover: 2 days

6. Via KWI - Total: €267.98
   BER-KWI: €117.99 (medium) - departs 2025-11-22
   KWI-SGN: €149.99 (low) - departs 2025-11-24
   Layover: 2 days

7. Via BOM - Total: €276.11
   BER-BOM: €193.99 (low) - departs 2025-11-18
   BOM-SGN: €82.12 (low) - departs 2025-11-19
   Layover: 1 days

8. Via BOM - Total: €276.99
   BER-BOM: €177.99 (low) - departs 2025-11-23
   BOM-SGN: €99.00 (low) - departs 2025-11-26
   Layover: 3 days

9. Via BOM - Total: €279.15
   BER-BOM: €179.99 (low) - departs 2025-12-02
   BOM-SGN: €99.16 (low) - departs 2025-12-03
   Layover: 1 days

10. Via BKK - Total: €279.55
   BER-BKK: €231.99 (low) - departs 2025-11-24
   BKK-SGN: €47.56 (low) - departs 2025-11-26
   Layover: 2 days

I guess this was kinda long. I am a bit disappointed in the result, since skyscanner and trip.com already find a pretty good price (279 Euros) if you are okay with a 22h transfer.