Midlandgeeks - Cloud Solutions for SME’s    

The Amadeus Flight Booking Journey - API Calls

The Amadeus Flight Booking Journey - API Calls

 

The Amadeus Flight Booking service consists of three separate API calls.  The first of these is the Flight Offers Search

The following code snippet represents the Flight Offers Search called from a python environment

# Install the Python library from https://pypi.org/project/amadeus

from amadeus import Client, ResponseError

 

amadeus = Client(

    client_id='your_client_id',

    client_secret='your_client_secret'

)

try:

    '''

    Find the cheapest flights from BHX to SVQ

    '''

    response = amadeus.shopping.flight_offers_search.get(

        currencyCode='GBP',

        originLocationCode='BHX',

        destinationLocationCode='SVQ',

        departureDate='2025-06-21',

        adults=1,

        children=0,

        infants=0,

        max=1)

    print(response.data)

except ResponseError as error:

    raise error

From a correctly invoked python environment - call flight_offers_search.py

(amadeus) [ec2-user@ip-172-31-12-162 amadeus-flight-booking-django]$ python api/flight_offers_search.py 

The service retures -

{
  "type": "flight-offer",
  "id": "1",
  "source": "GDS",
  "instantTicketingRequired": false,
  "nonHomogeneous": false,
  "oneWay": false,
  "isUpsellOffer": false,
  "lastTicketingDate": "2025-05-22",
  "lastTicketingDateTime": "2025-05-22",
  "numberOfBookableSeats": 9,
  "itineraries": [
    {
      "duration": "PT15H25M",
      "segments": [
        {
          "departure": {"iataCode": "BHX", "at": "2025-06-21T17:35:00"},
          "arrival": {"iataCode": "AMS", "at": "2025-06-21T19:50:00"},
          "carrierCode": "KL",
          "number": "1048",
          "aircraft": {"code": "73H"},
          "operating": {"carrierCode": "KL"},
          "duration": "PT1H15M",
          "id": "1",
          "numberOfStops": 0,
          "blacklistedInEU": false
        },
        {
          "departure": {"iataCode": "AMS", "at": "2025-06-22T07:05:00"},
          "arrival": {"iataCode": "SVQ", "at": "2025-06-22T10:00:00"},
          "carrierCode": "KL",
          "number": "2544",
          "aircraft": {"code": "32Q"},
          "operating": {"carrierCode": "HV"},
          "duration": "PT2H55M",
          "id": "2",
          "numberOfStops": 0,
          "blacklistedInEU": false
        }
      ]
    }
  ],
  "price": {
    "currency": "GBP",
    "total": "166.17",
    "base": "86.00",
    "fees": [
      {"amount": "0.00", "type": "SUPPLIER" },
      {"amount": "0.00", "type": "TICKETING"}
    ],
    "grandTotal": "166.17"
  },
  "pricingOptions": {
    "fareType": ["PUBLISHED"],
    "includedCheckedBagsOnly": true
  },
  "validatingAirlineCodes": ["AF"],
  "travelerPricings": [
    {
      "travelerId": "1",
      "fareOption": "STANDARD",
      "travelerType": "ADULT",
      "price": {"currency": "GBP", "total": "166.17", "base": "86.00"},
      "fareDetailsBySegment": [
        {
          "segmentId": "1",
          "cabin": "ECONOMY",
          "fareBasis": "GYQFBBSA",
          "brandedFare": "STANDARD",
          "brandedFareLabel": "ECONOMY STANDARD",
          "class": "G",
          "includedCheckedBags": {"quantity": 1},
          "includedCabinBags": {"quantity": 1},
          "amenities": [
            {
              "description": "SNACK",
              "isChargeable": false,
              "amenityType": "MEAL",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "BEVERAGE",
              "isChargeable": false,
              "amenityType": "MEAL",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "SEAT SELECTION",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "MILEAGE ACCRUAL",
              "isChargeable": false,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "UPGRADE ELIGIBILITY",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "CHANGEABLE TICKET",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            }
          ]
        },
        {
          "segmentId": "2",
          "cabin": "ECONOMY",
          "fareBasis": "GYQFBBSA",
          "brandedFare": "STANDARD",
          "brandedFareLabel": "ECONOMY STANDARD",
          "class": "G",
          "includedCheckedBags": {"quantity": 1},
          "amenities": [
            {
              "description": "SNACK",
              "isChargeable": false,
              "amenityType": "MEAL",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "BEVERAGE",
              "isChargeable": false,
              "amenityType": "MEAL",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "SEAT SELECTION",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "MILEAGE ACCRUAL",
              "isChargeable": false,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "UPGRADE ELIGIBILITY",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            },
            {
              "description": "CHANGEABLE TICKET",
              "isChargeable": true,
              "amenityType": "BRANDED_FARES",
              "amenityProvider": {"name": "BrandedFare"}
            }
          ]
        }
      ]
    }
  ]
}
 

Amadeus Flight API xml cleansing

 

The flight search xml returned from an API call seems to require cleansing in order to use standard xml manipulation on the returned data.  In the crudest form the following will clean the xml in order for commands like jq to run gracefully -

 

python api/flight_offers_search.py | sed  s/\'\/\"\/g | sed s/False/\"False\"/g | sed s/True/\"True\"/g | jq .

Effectively this series of sed manipulation 1.  Changes  the data for the xml parameter from single quote to double-quote 2. Inserts double-quotes around parameters returning a False response 3.  Inserts a double-quote around parameters returning a True response.  This is ultimately piped to jq to prettify the xml.

The successful generation of flight offers marks the end of the first api call.  The second api call, flight offers price is required to confirm the selected flight is still valid.  This call is typically invoked on booking.

(amadeus) [ec2-user@ip-172-31-12-162 amadeus-flight-booking-django]$ python api/code-example-price.py

The call returns the proposed booking details with any caveats to the original request if any.

{
  "warnings": [
    {
      "code": 0,
      "title": "PricingOrFareBasisDiscrepancyWarning",
      "detail": "Actual price and/or fare basis for some passengers is different from requested ones",
      "status": 200
    }
  ],
  "data": {
    "type": "flight-offers-pricing",
    "flightOffers": [
      {
        "type": "flight-offer",
        "id": "1",
        "source": "GDS",
        "instantTicketingRequired": false,
        "nonHomogeneous": false,
        "paymentCardRequired": false,
        "lastTicketingDate": "2025-05-27",
        "itineraries": [
          {
            "segments": [
              {
                "departure": {
                  "iataCode": "BHX",
                  "at": "2025-06-21T17:35:00"
                },
                "arrival": {
                  "iataCode": "AMS",
                  "at": "2025-06-21T19:50:00"
                },
                "carrierCode": "KL",
                "number": "1048",
                "aircraft": {
                  "code": "73H"
                },
                "operating": {
                  "carrierCode": "KL"
                },
                "duration": "PT1H15M",
                "id": "17",
                "numberOfStops": 0,
                "co2Emissions": [
                  {
                    "weight": 64,
                    "weightUnit": "KG",
                    "cabin": "ECONOMY"
                  }
                ]
              },
              {
                "departure": {
                  "iataCode": "AMS",
                  "at": "2025-06-22T07:05:00"
                },
                "arrival": {
                  "iataCode": "SVQ",
                  "at": "2025-06-22T10:00:00"
                },
                "carrierCode": "KL",
                "number": "2544",
                "aircraft": {
                  "code": "32Q"
                },
                "operating": {
                  "carrierCode": "HV"
                },
                "duration": "PT2H55M",
                "id": "18",
                "numberOfStops": 0,
                "co2Emissions": [
                  {
                    "weight": 117,
                    "weightUnit": "KG",
                    "cabin": "ECONOMY"
                  }
                ]
              }
            ]
          }
        ],
        "price": {
          "currency": "GBP",
          "total": "177.17",
          "base": "97.00",
          "fees": [
            {
              "amount": "0.00",
              "type": "SUPPLIER"
            },
            {
              "amount": "0.00",
              "type": "TICKETING"
            },
            {
              "amount": "0.00",
              "type": "FORM_OF_PAYMENT"
            }
          ],
          "grandTotal": "177.17",
          "billingCurrency": "GBP"
        },
        "pricingOptions": {
          "fareType": [
            "PUBLISHED"
          ],
          "includedCheckedBagsOnly": true
        },
        "validatingAirlineCodes": [
          "AF"
        ],
        "travelerPricings": [
          {
            "travelerId": "1",
            "fareOption": "STANDARD",
            "travelerType": "ADULT",
            "price": {
              "currency": "GBP",
              "total": "177.17",
              "base": "97.00",
              "taxes": [
                {
                  "amount": "10.50",
                  "code": "CJ"
                },
                {
                  "amount": "20.00",
                  "code": "YQ"
                },
                {
                  "amount": "1.25",
                  "code": "YR"
                },
                {
                  "amount": "13.00",
                  "code": "GB"
                },
                {
                  "amount": "12.10",
                  "code": "RN"
                },
                {
                  "amount": "23.32",
                  "code": "UB"
                }
              ],
              "refundableTaxes": "58.92"
            },
            "fareDetailsBySegment": [
              {
                "segmentId": "17",
                "cabin": "ECONOMY",
                "fareBasis": "XYQDBBSA",
                "brandedFare": "STANDARD",
                "class": "X",
                "includedCheckedBags": {
                  "quantity": 1
                }
              },
              {
                "segmentId": "18",
                "cabin": "ECONOMY",
                "fareBasis": "XYQDBBSA",
                "brandedFare": "STANDARD",
                "class": "X",
                "includedCheckedBags": {
                  "quantity": 1
                }
              }
            ]
          }
        ]
      }
    ],
    "bookingRequirements": {
      "emailAddressRequired": true,
      "mobilePhoneNumberRequired": true
    }
  },
  "dictionaries": {
    "locations": {
      "BHX": {
        "cityCode": "BHX",
        "countryCode": "GB"
      },
      "AMS": {
        "cityCode": "AMS",
        "countryCode": "NL"
      },
      "SVQ": {
        "cityCode": "SVQ",
        "countryCode": "ES"
      }
    }
  }
} 
Caveats

This blog is transiting from a tech blog to a Travel and Arts blog. The simple reason is that I have now retired from the tech field and mostly try to spend my time in the travel and arts space. It is intended to emphasize a cultural slant through art on my travel tours by promoting various artists and their work which is or has been popular in Trinidad and Tobago and throughout the Caribbean...

Know more!