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"
}
}
}
}