# Flight Offers API: Amadeus Self-Service Alternative (`kuezi/flight-offers-api`) Actor

Live flight prices with Amadeus Self-Service-style inputs and JSON: Flight Offers Search, Cheapest Date Search and Price Analysis, powered by Google Flights. For code that broke when Amadeus Self-Service shut down. Not affiliated with Amadeus.

- **URL**: https://apify.com/kuezi/flight-offers-api.md
- **Developed by:** [Ishema Hugues](https://apify.com/kuezi) (community)
- **Categories:** Travel, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Flight Offers API: an Amadeus Self-Service alternative

Amadeus decommissioned its **Self-Service APIs on 17 July 2026**. API keys stopped working and the official SDKs were archived. If your app, fare tracker, travel bot or class project used **Flight Offers Search**, **Flight Cheapest Date Search** or **Flight Price Analysis**, this Actor gives you the same calls with **Amadeus-style parameters and JSON**, using live prices from Google Flights.

- **Same parameter names:** `originLocationCode`, `destinationLocationCode`, `departureDate`, `returnDate`, `adults`, `children`, `infants`, `travelClass`, `nonStop`, `includedAirlineCodes`, `excludedAirlineCodes`, `maxPrice`, `max`, `currencyCode`.
- **Same response shape:** `RESPONSE.data` holds `flight-offer`, `flight-date` or `itinerary-price-metric` objects with `itineraries[].segments[]`, `departure.iataCode` / `departure.at`, `carrierCode`, `number`, ISO-8601 `duration`, `price.total` / `price.grandTotal` as strings, plus `dictionaries.carriers`.
- **No API key from an airline or GDS**, no approval queue, no monthly plan. You pay per search.
- **Not affiliated with or endorsed by Amadeus IT Group.** This is an independent replacement for the read-only price endpoints.

Step-by-step migration guide with real outputs: [Amadeus Self-Service shut down on July 17. Here's a drop-in replacement for flight prices](https://dev.to/ishemah/amadeus-self-service-shut-down-on-july-17-heres-a-drop-in-replacement-for-flight-prices-1npn).

### What it replaces (and what it doesn't)

| Amadeus Self-Service call | Here | Notes |
|---|---|---|
| Flight Offers Search `GET /v2/shopping/flight-offers` | `endpoint: "flight-offers"` | Live offers, best and cheapest first. Round trips: the price is the trip total; the offer lists the outbound itinerary |
| Flight Cheapest Date Search `GET /v1/shopping/flight-dates` | `endpoint: "cheapest-date"` | Scans every departure day in a range (max 90). One trip length per run (`duration: 7`), not a range |
| Flight Price Analysis `GET /v1/analytics/itinerary-price-metrics` | `endpoint: "price-metrics"` | MINIMUM / FIRST / MEDIUM / THIRD / MAXIMUM from Google's recent price history for that date, plus Google's own low/typical/high verdict |
| Flight Offers Price, Flight Create Orders, Seat Maps | ✘ | No booking, no fare rules, no seat maps. For booking you need a booking API (an airline, a consolidator or Amadeus Enterprise) |

Fields Google Flights doesn't publish are `null`: `numberOfBookableSeats`, `lastTicketingDate`, `price.base`, `aircraft.code` (the aircraft name is in `aircraft.name`). Extras Amadeus never had are under `googleFlights`: CO₂, legroom, layovers, Google's price level and a link to the search.

### Migrate in 5 minutes (Python)

Before, with the archived `amadeus` SDK:

```python
response = amadeus.shopping.flight_offers_search.get(
    originLocationCode="JFK", destinationLocationCode="LAX",
    departureDate="2026-11-12", adults=1, max=10)
for offer in response.data:
    print(offer["price"]["total"], offer["itineraries"][0]["segments"][0]["carrierCode"])
```

After, with `pip install apify-client` (version 3.x):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

def flight_offers_search(**params):
    run = client.actor("kuezi/flight-offers-api").call(logger=None, run_input={"endpoint": "flight-offers", **params})
    return client.key_value_store(run.default_key_value_store_id).get_record("RESPONSE")["value"]

response = flight_offers_search(originLocationCode="JFK", destinationLocationCode="LAX",
                                departureDate="2026-11-12", adults=1, max=10)
for offer in response["data"]:
    print(offer["price"]["total"], offer["itineraries"][0]["segments"][0]["carrierCode"])
```

The loop body is unchanged. Only `response.data` becomes `response["data"]`.

**Node.js** (`npm i apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('kuezi/flight-offers-api').call({ endpoint: 'cheapest-date', origin: 'SFO', destination: 'HNL', departureDate: '2026-11-01,2026-11-30' });
const { value: response } = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('RESPONSE');
console.log(response.data[0]); // cheapest date first
```

**Plain HTTP** (one request, waits for the result):

```bash
curl -X POST "https://api.apify.com/v2/acts/kuezi~flight-offers-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"endpoint":"flight-offers","originLocationCode":"LHR","destinationLocationCode":"JFK","departureDate":"2026-12-01","max":5}'
```

### Example output

`flight-offers` (one object per offer, trimmed):

```json
{
  "type": "flight-offer",
  "id": "1",
  "source": "GOOGLE_FLIGHTS",
  "oneWay": true,
  "numberOfBookableSeats": null,
  "itineraries": [{
    "duration": "PT6H8M",
    "segments": [{
      "departure": { "iataCode": "JFK", "at": "2026-11-12T12:00:00" },
      "arrival": { "iataCode": "LAX", "at": "2026-11-12T15:08:00" },
      "carrierCode": "DL", "number": "1788",
      "aircraft": { "code": null, "name": "Airbus A330" },
      "duration": "PT6H8M", "numberOfStops": 0
    }]
  }],
  "price": { "currency": "USD", "total": "204.00", "base": null, "grandTotal": "204.00" },
  "validatingAirlineCodes": ["DL"],
  "googleFlights": { "isBest": true, "stops": 0, "emissionsGrams": 261000, "priceLevel": "typical", "typicalPriceLow": 144, "typicalPriceHigh": 240 }
}
```

`cheapest-date`, sorted cheapest first:

```json
{ "type": "flight-date", "origin": "SFO", "destination": "HNL", "departureDate": "2026-11-01", "returnDate": null, "price": { "total": "163.00" }, "priceLevel": "low" }
```

`price-metrics` (a real run on 2026-10-02 for 12 Nov, over 61 days of history):

```json
{
  "type": "itinerary-price-metric",
  "origin": { "iataCode": "JFK" }, "destination": { "iataCode": "LAX" },
  "departureDate": "2026-11-12", "currencyCode": "USD", "oneWay": true,
  "priceMetrics": [
    { "amount": "167.00", "quartileRanking": "MINIMUM" }, { "amount": "178.00", "quartileRanking": "FIRST" },
    { "amount": "178.00", "quartileRanking": "MEDIUM" }, { "amount": "204.00", "quartileRanking": "THIRD" },
    { "amount": "215.00", "quartileRanking": "MAXIMUM" }
  ],
  "currentPrice": "204.00", "googlePriceLevel": "typical", "googleTypicalRange": { "low": "144.00", "high": "240.00" }
}
```

The run's status message is a one-line answer, such as "30 departure dates priced for SFO-HNL (one-way). Cheapest 163.00 USD on 2026-11-01 (+11 more dates at that price); priciest 444.00 on 2026-11-20". AI agents calling the Actor through the [Apify MCP server](https://mcp.apify.com) get the answer without reading the dataset.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Google Flights search that returned results (`search`) | $0.003 |
| Flight offer saved (`flight-offer`, flight-offers endpoint only) | $0.0005 |

- One Flight Offers Search with 10 offers: **$0.008**.
- A 30-day Cheapest Date Search: **$0.09**.
- One Price Analysis: **$0.003**.

Failed searches and searches with no flights are free. Set a maximum cost per run and the Actor stops cleanly.

### FAQ

**Why did Amadeus Self-Service stop working?** Amadeus decommissioned the Self-Service portal and its APIs on 17 July 2026; its developer site now says so. Amadeus Enterprise APIs continue, for companies with a commercial agreement.

**Are these the same prices Amadeus returned?** No. Amadeus returned GDS fares; this Actor returns what Google Flights shows a shopper in the chosen country, which includes low-cost carriers and airline-direct fares. Treat prices as shopping prices, not bookable fares.

**Can I book with this?** No. It's read-only price data. Use the `googleFlights.url` link, or a booking API.

**How fast is it?** In our tests on 2026-10-02, one Flight Offers Search took 5 seconds and a 30-day Cheapest Date Search took 18–21 seconds (10 searches run in parallel). A single slow search can add 10–20 seconds, because it is retried on a fresh IP.

**Multi-city, flexible origins, airport/city search?** Not yet. Use IATA airport codes. Ask in the Issues tab if you need one of these.

### More from the same developer

- [Google Flights Scraper](https://apify.com/kuezi/google-flights-scraper): the full Google Flights data (segments, layovers, legroom, CO₂) for many routes at once.
- [Google Hotels Scraper](https://apify.com/kuezi/google-hotels-scraper): hotel prices from 18–20 booking sites per hotel. Useful if you used Amadeus Hotel Search.

# Actor input Schema

## `endpoint` (type: `string`):

Which retired Amadeus Self-Service call to replace. flight-offers = Flight Offers Search (GET /v2/shopping/flight-offers). cheapest-date = Flight Cheapest Date Search (GET /v1/shopping/flight-dates). price-metrics = Flight Price Analysis (GET /v1/analytics/itinerary-price-metrics).

## `originLocationCode` (type: `string`):

3-letter IATA airport code, e.g. JFK. Aliases accepted: origin, originIataCode.

## `destinationLocationCode` (type: `string`):

3-letter IATA airport code, e.g. LAX. Aliases accepted: destination, destinationIataCode.

## `departureDate` (type: `string`):

YYYY-MM-DD. Leave empty for 21 days from today. For cheapest-date, a range like 2026-11-01,2026-11-30 (max 90 days); a single date scans 30 days from it.

## `returnDate` (type: `string`):

YYYY-MM-DD for a round trip. Leave empty for one-way. Round-trip prices are the total for the trip; the offer lists the outbound itinerary.

## `duration` (type: `integer`):

Round-trip length for cheapest-date, e.g. 7. Leave empty for one-way. One value only (Amadeus ranges like 1,15 are not supported).

## `oneWay` (type: `boolean`):

Defaults to one-way unless you set a trip length.

## `adults` (type: `integer`):

Travelers aged 12+.

## `children` (type: `integer`):

Aged 2-11.

## `infants` (type: `integer`):

Under 2, on an adult's lap, as in Amadeus.

## `travelClass` (type: `string`):

Cabin, using Amadeus values.

## `nonStop` (type: `boolean`):

Only direct flights.

## `includedAirlineCodes` (type: `string`):

Comma-separated IATA codes, e.g. DL,UA. Keeps offers with at least one segment on these airlines.

## `excludedAirlineCodes` (type: `string`):

Comma-separated IATA codes to drop.

## `maxPrice` (type: `integer`):

Total for all travelers, in the chosen currency. 0 = no limit.

## `max` (type: `integer`):

How many offers to return, best and cheapest first. Google usually has 30-100 per search.

## `currencyCode` (type: `string`):

3-letter code, e.g. USD, EUR, GBP.

## `country` (type: `string`):

Google country code (gl), e.g. us, gb, de. Prices can differ by country.

## `language` (type: `string`):

Interface language (hl), e.g. en.

## `maxConcurrency` (type: `integer`):

For cheapest-date scans. At 10, a 30-day scan finishes in about 20 seconds.

## `maxRetries` (type: `integer`):

Each retry uses a fresh IP.

## `proxyConfiguration` (type: `object`):

Residential US proxies are the reliable default for Google.

## Actor input object example

```json
{
  "endpoint": "flight-offers",
  "originLocationCode": "JFK",
  "destinationLocationCode": "LAX",
  "adults": 1,
  "children": 0,
  "infants": 0,
  "travelClass": "ECONOMY",
  "nonStop": false,
  "maxPrice": 0,
  "max": 50,
  "currencyCode": "USD",
  "country": "us",
  "language": "en",
  "maxConcurrency": 10,
  "maxRetries": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `response` (type: `string`):

Drop-in for code that read Amadeus response.data.

## `items` (type: `string`):

The same objects as RESPONSE.data, as dataset rows.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "originLocationCode": "JFK",
    "destinationLocationCode": "LAX",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kuezi/flight-offers-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "originLocationCode": "JFK",
    "destinationLocationCode": "LAX",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("kuezi/flight-offers-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "originLocationCode": "JFK",
  "destinationLocationCode": "LAX",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call kuezi/flight-offers-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kuezi/flight-offers-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/2pu4VnHQveIameiks/builds/RwzD4FZArya1hAsng/openapi.json
