# Award Flight Scraper - Availability, Miles, Taxes & Seats (`abotapi/flightpoints-award-scraper`) Actor

Scrape award flight availability from Flightpoints.com and Roame.travel by route and date. Compare miles, taxes, available seats, cabins, stops, fare classes, loyalty programs and operating airlines. Includes per-cabin details across dozens of loyalty programs.

- **URL**: https://apify.com/abotapi/flightpoints-award-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Travel, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 18 total users, 7 monthly users, 96.2% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 award itineraries

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

## FlightPoints & Roame Award Flight Scraper: Miles, Taxes, Seats and Cabins by Route

FlightPoints and Roame turn public airline award search engines into one clean data feed. Give any route and date and get the miles, taxes, available seats, cabins, stops, loyalty program and operating airline for every itinerary found on both sources, normalized into a single schema. Search one route, paste a bulk list of routes, or paste search links directly, then export the results to JSON, CSV or Excel, or pull them straight into your app through the API.

### Why This Scraper?

- **Two sources, one schema.** FlightPoints and Roame results are normalized into the same fields, so one run covers more loyalty programs than either source alone.
- **Per-cabin detail.** Economy, premium, business and first each carry their own miles, taxes, seat count and stops, when award space exists for that cabin.
- **Dozens of loyalty programs**, across Star Alliance, oneworld and SkyTeam, from a single search.
- **Optional per-flight detail.** Turn on Add flight detail for segments with layover times, aircraft, cash prices and a booking link.
- **One route or a bulk campaign.** Search a single origin, destination and date, pass a list of routes, or paste search links.
- **Built for monitoring.** Incremental mode reports only new and updated itineraries on repeated runs, and a genuine outage fails the run loudly instead of quietly returning nothing.
- **Pipe results into the apps you already use** through MCP connectors, without changing what lands in the dataset.

### Use Cases

- **Points and miles hunters:** watch specific routes for award seats opening up in a preferred cabin or program.
- **Travel content and award-booking services:** compare miles, taxes and seat counts across programs for a route in one run.
- **Availability and price monitors:** schedule Incremental mode runs to catch new award openings or changes in miles, taxes or seats.
- **Travel-hacking dashboards and bots:** feed live award availability into your own site, alert or tool.
- **Bulk route research:** search many city pairs and dates in one run instead of one search at a time.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `id` | `"fp\|AA\|JFK\|LHR\|2026-10-29"` |
| `source` | `"flightpoints"` (also `"roame"`) |
| `origin` / `destination` | `"JFK"` / `"LHR"` |
| `departureDate` | `"2026-10-29"` |
| `program` | `"AA"` |
| `programName` | `"AAdvantage"` |
| `airline` | `"American Airlines"` |
| `alliance` | `"oneworld"` |
| `numStops` | `0` |
| `durationMinutes` | `420` (`null` on FlightPoints summary rows) |
| `cabins.economy.miles` | `30000` |
| `cabins.economy.taxes` | `5.6` |
| `cabins.economy.seats` | `1` |
| `cabins.economy.stops` | `0` |
| `cabins.economy.airlines` | `["AA", "BA"]` |
| `cabins.business.miles` | `57500` |
| `cabins.business.taxes` | `19.7` |
| `lastSeen` | `"2026-08-07T19:35:17Z"` |
| `scrapedAt` | `"2026-08-08T09:00:00Z"` |
| `changeType` | `"NEW"` (incremental mode only) |
| `changedFields` | `["cabins"]` (incremental mode, `UPDATED` rows only) |
| `firstSeenAt` / `lastSeenAt` | incremental mode timestamps |

Roame rows carry one fare per record instead of a full per-program breakdown: `fareClass`, `cabinClasses`, `awardPoints`, `surcharge`, `roameScore`, `availableSeats`, `operatingAirlines`, `flightNumberOrder`, `equipmentTypes`, `allAirports`, `itineraryHash` and `md5` sit alongside the same `origin`, `destination`, `departureDate`, `program`, `numStops` and `cabins` fields shown above. Roame rows also carry a `bookingUrl` and a `segments` array (same shape as the FlightPoints detail segments below). With Add flight detail on, FlightPoints also returns one row per individual flight, adding `departureTime`, `arrivalDate`, `arrivalTime`, `dayCount`, `distance`, `bookingUrl` and a `segments` array (one entry per flight leg, each with `segmentNumber`, `origin`, `destination`, `departureTime`, `arrivalTime`, `flightNumber`, `airlineCode`, `aircraft`, `layoverTime`, `travelMinutes` and `airlineName`).

### How to Use

1. Pick a **mode**: `search` (route and date, single or bulk) or `url` (paste search links).
2. Fill in the route or links for that mode, then set the filters that apply to both modes: cabin, the plus or minus days window and direct only.
3. Set **Max itineraries** to control run size and cost, and turn on **Add flight detail** if you also want segments, stopovers and a booking link.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Single route:**

```json
{
  "mode": "search",
  "origin": "JFK",
  "destination": "LHR",
  "departureDate": "2026-10-29",
  "sources": ["flightpoints", "roame"]
}
```

**Bulk routes, direct flights only:**

```json
{
  "mode": "search",
  "routes": [
    { "origin": "JFK", "destination": "LHR", "departureDate": "2026-10-29" },
    "LAX,NRT,2026-11-05"
  ],
  "directOnly": true,
  "maxItems": 100
}
```

**Pasted search links:**

```json
{
  "mode": "url",
  "urls": [
    "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-10-29",
    "https://roame.travel/search?from=JFK&to=CDG&departureDate=2026-11-02"
  ]
}
```

##### URL mode

Url mode with the links field untouched scrapes one example per link shape that carries a route (a link with no route, such as a bare `/search`, is not in the default list because it scrapes nothing). Links with several origins or destinations expand to every origin and destination pair, and `maxItems` still caps the total.

| Link shape | Example |
| --- | --- |
| FlightPoints search | `flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16` |
| FlightPoints, www host, several origins | `www.flightpoints.com/search?origins=JFK,EWR&destinations=LHR&date=2026-11-16` |
| FlightPoints with `cabin` and `direct` | `flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16&cabin=business&direct=true` |
| FlightPoints, http, no date | `flightpoints.com/search?origins=JFK&destinations=LHR` (date defaults to 30 days out) |
| Roame search | `roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16` |
| Roame with `searchClass` | `roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16&searchClass=BUS` |
| Roame alternate params | `roame.travel/search?origin=JFK&destination=LHR&date=2026-11-16` |

`cabin` / `class` / `searchClass` (economy, premium, business, first) and `direct=true` in a link override the Cabin and Direct-only filters for that link, on both sources: a FlightPoints link with `cabin=business` keeps only rows that have business miles, and `direct=true` keeps only nonstop rows. A link with no route (for example a bare `/search`) is skipped with a warning.

**Per-flight detail plus recurring monitoring:**

```json
{
  "mode": "search",
  "origin": "SFO",
  "destination": "NRT",
  "departureDate": "2026-11-15",
  "fetchDetails": true,
  "incrementalMode": true,
  "stateKey": "sfo-nrt-daily"
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/flightpoints-award-scraper").call(run_input={
    "mode": "search", "origin": "JFK", "destination": "LHR", "departureDate": "2026-10-29"
})
for itinerary in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(itinerary["program"], itinerary["cabins"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/flightpoints-award-scraper').call({
  mode: 'search', origin: 'JFK', destination: 'LHR', departureDate: '2026-10-29',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset ID and the actor skips every itinerary already collected there, so you don't pay twice.
- **Incremental mode** (`incrementalMode`) is for scheduled runs over the same routes or links. Each itinerary is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), or `EXPIRED` (only once a run has scanned this search's full scope end to end, and only with `emitExpired` on). `REAPPEARED` only appears after that: once an itinerary has actually been marked `EXPIRED` in a previous run, a later run that finds it again marks it `REAPPEARED`, not `NEW`. `stateKey` names or shares the stored state; leave it blank and the actor derives one from your routes or links and settings, so different searches never mix state. With incremental mode off, output is exactly as before.

  **What is compared:** every output field except the volatile ones. Miles/points, taxes or surcharge, seats, stops, airlines, times and segment details all count toward `UPDATED`. The source's last-seen/update timestamps, the scrape time and the derived Roame score and premium ratio never do: they stay in the output but never trigger `UPDATED` or appear in `changedFields`, including inside `cabins` and `segments`. Whole numbers compare equal whether stored as `25` or `25.0`. Use `ignoreFieldsForChanges` to exclude more fields (a bare name such as `seats` matches at any depth; a dotted path such as `cabins.economy.seats` matches one field). Changing the list never re-bills your existing baseline.

#### Dataset views and run summary

The dataset has four views: **overview** (route, program, per-cabin miles and taxes), **detail** (full per-cabin and Roame fare fields), **changes** (incremental mode status and changed fields) and **segments** (per-flight legs). A run summary is also saved to the key-value store under `OUTPUT`.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped itineraries into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

1. Authorize a connector once under **Apify, Settings, Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. If the picker is empty, you haven't authorized a connector yet.
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.
4. Use `maxNotifyListings` to cap how many itineraries are written to each connector per run. This does not affect the dataset.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave `mcpConnectors` empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (routes and filters) or `url` (pasted links). |
| `origin` | string | none (prefill: `JFK`) | Origin airport for a single-route search: a 3-letter IATA code or an airport / city name (looked up in the source's public airport list, case-insensitive). A name that matches no airport, or several, is logged as an error and that route is skipped. Used only when `routes` is empty; if left blank in that case, the actor falls back to `JFK`. |
| `destination` | string | none (prefill: `LHR`) | Destination airport: a 3-letter IATA code or an airport / city name, resolved the same way as the origin. Same fallback behavior, to `LHR`, when `routes` is empty and this is left blank. |
| `departureDate` | string | none (prefill: empty) | `YYYY-MM-DD`, roughly 60 days forward. If left blank, the actor fills in a date about 30 days out before querying either source, since a blank date is rejected by the award engines. |
| `routes` | array | none | Bulk list of `{origin, destination, departureDate}` objects or `"ORIGIN,DEST,DATE"` lines (origin and destination may be codes or airport / city names). Overrides the single-route fields above when present. |
| `urls` | array | one example link per supported shape (see URL mode) | Pasted FlightPoints or Roame search links (url mode). |
| `sources` | array | `["flightpoints", "roame"]` | Which award-search engines to query. |
| `startDate` | string | none | First day of a date window (search mode, single route only; window capped at 60 days). Overrides Departure date. |
| `endDate` | string | none | Last day of the date window (`YYYY-MM-DD`). |
| `cabin` | string | any | Keep only itineraries with award space in this cabin (`economy`, `premiumEconomy`, `business`, `first`), for both sources. |
| `maxMiles` | integer | none | Keep itineraries whose selected (or any) cabin costs at most this many miles. |
| `maxCashTaxes` | number | none | Keep itineraries whose selected (or any) cabin has taxes and fees at most this amount. |
| `minSeats` | integer | none | Keep itineraries whose selected (or any) cabin has at least this many seats. |
| `nonstop` | boolean | `false` | Alias of `directOnly`; either one turns the filter on. |
| `issuers` | array | all | Keep only these loyalty program codes, for example `CX`, `AA`. |
| `operatingAirlines` | array | all | Keep itineraries operated by at least one of these airline codes, for example `BA`, `VS`. |
| `sortBy` | string | none | Within each batch of results, list itineraries offering this cabin first, cheapest miles first. |
| `searchClass` | string | `ECON` | Cabin filter for Roame (`ECON`, `PREM`, `BUS`, `FIRST`). FlightPoints returns all cabins regardless. |
| `daysAround` | integer | `0` | Widen the search by this many days on each side of the departure date (0 to 7). |
| `directOnly` | boolean | `false` | Return non-stop itineraries only. Applies to both sources. |
| `maxItems` | integer | `20` | Cap on itineraries returned across the whole run. `0` means unlimited. |
| `fetchDetails` | boolean | `false` | Add per-flight segments, stopovers and booking links from FlightPoints. Billed per enriched itinerary. |
| `resumeFromRunId` | string | none | Continue one specific previous run or dataset without re-collecting or re-billing what it already has. |
| `incrementalMode` | boolean | `false` | Return only new, updated (and optionally expired or reappeared) itineraries on repeated runs over the same search. |
| `ignoreFieldsForChanges` | array | none | Incremental mode only: extra field names or dotted paths that never count as a change (they stay in the output). |
| `stateKey` | string | none | Name or share an incremental-mode state. Left blank, a key is derived automatically from the search. |
| `emitUnchanged` | boolean | `false` | Also return, and bill, itineraries that have not changed since the last run. |
| `emitExpired` | boolean | `false` | Also return, and bill, itineraries that were tracked before but are no longer found, once a run has scanned the full search. |
| `proxy` | object | `{ "useApifyProxy": true }` | Apify Proxy settings. The default (datacenter) connection serves both sources and was measured through the Apify proxy; no residential tier is required (see Plan Requirement). You can pick another group or supply your own proxy URLs. |
| `mcpConnectors` | array | none | Optional: send a summary of each itinerary to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | none | Notion connector only: page under which item pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run (1 to 1000). Does not affect the dataset. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

```json
{
  "id": "fp|AA|JFK|LHR|2026-10-29",
  "source": "flightpoints",
  "origin": "JFK",
  "destination": "LHR",
  "departureDate": "2026-10-29",
  "program": "AA",
  "programName": "AAdvantage",
  "airline": "American Airlines",
  "alliance": "oneworld",
  "durationMinutes": null,
  "numStops": 0,
  "cabins": {
    "economy": { "miles": 30000, "taxes": 5.6, "seats": 1, "stops": 0, "airlines": ["AA", "BA"] },
    "business": { "miles": 57500, "taxes": 19.7, "seats": 1, "stops": 0, "airlines": ["AA", "BA"] }
  },
  "lastSeen": "2026-08-07T19:35:17Z",
  "scrapedAt": "2026-08-08T09:00:00Z"
}
```

### Plan Requirement

The actor uses the default Apify Proxy setting. The default datacenter connection was measured to serve both sources (the Flightpoints data service answered with HTTP 200 and the Roame service was reachable), so **no residential proxy tier is required**. Apify free plans do not include Apify Proxy at all, so a free-plan run falls back to a backup connection automatically (see the log lines below); you can also supply your own proxy URLs.

What you will see if the connection is a problem:

- If the default connection is not available to the run, the log shows this warning block: "The selected connection is unavailable to this run." / "Apify free plans do not include residential proxies." / "Continuing on a backup connection; some pages may still be unavailable." / "For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs." The actor then continues on the backup connection ("Switching to a backup gateway for the rest of this run." when it moves over mid-run).
- When the backup connection serves data, the log says: "Served over the backup connection (the default connection was unavailable)."
- If every connection is refused and no page loads, the run fails with: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
- If only the backup connection ran and still could not load the pages, the run fails with: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Flightpoints pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
- If requests simply fail, the run fails with: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

Check the **Pricing** tab on the actor page for current plan and usage rates.

### FAQ

#### How much does it cost?

You pay a flat charge when a run starts, plus a per-itinerary charge for each row returned in the dataset, plus a small extra charge per itinerary only when **Add flight detail** is switched on. The **Pricing** tab on the actor page shows current rates. Use **Max itineraries** to cap the cost of any run.

#### Is it legal to scrape FlightPoints.com?

This actor reads only publicly available search results from FlightPoints.com and Roame.travel; it does not sign in to any account or read anything behind a login. Award seats and prices are not guaranteed to still be available or bookable by the time you check them, since availability changes constantly. You are responsible for using the data in line with each site's terms and the laws that apply to you, and for getting legal advice before any commercial redistribution.

#### Can I monitor the same routes for award openings on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode** for the same routes or links. The first run returns every itinerary as `NEW`. Later runs return only `NEW` and `UPDATED` itineraries by default; unchanged ones are suppressed and not billed unless you turn on **Emit unchanged**. `REAPPEARED` is not produced by default: it only appears after a prior run has fully scanned the search with **Emit expired** on and marked a missing itinerary `EXPIRED`. Without that, an itinerary that briefly disappears and comes back is simply reported again as `UPDATED` or `UNCHANGED`, never `REAPPEARED`.

#### Why are some cabins or programs missing from a result?

A cabin only appears inside `cabins` when the source reports real award space for it on that exact itinerary, and a program or airline only appears when it actually has inventory for the route, date and cabin you searched. This is expected: award availability is sparse and volatile, so the same route and date can show different cabins minutes apart. A search with genuinely no award seats for that route and date is a normal, successful result, not a failure.

#### Why did my run fail instead of returning an empty dataset?

A run fails when it ends with no itineraries at all and at least one route, source or pasted link could not be completed (it failed, timed out, or a pasted link was not recognized), which is a genuine outage on the connection or on the source's side. In that case the run stops with a clear message instead of quietly reporting zero results, and it names whether the connection itself was refused (a plan or access limit) or the source simply could not be reached. The run reports success with an empty dataset only when every route and source completed and genuinely found no award seats for that date and cabin, since that is a normal outcome for award search, not a problem. If only some routes or sources could not be confirmed while others succeeded and scanned at least one itinerary, you still get whatever those found, and the run succeeds. In Incremental mode, a scheduled run where every tracked itinerary comes back unchanged also reports success quietly, with a status message noting that nothing changed, rather than the empty-result warning.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push itineraries into Notion, Linear or Airtable.

### 🔗 Want more travel data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>🧩 <a href="https://apify.com/abotapi/flightradar24-live-flight-tracker"><b>Flightradar24</b></a><br>Live aircraft positions by map area (callsign, lat/lng, altitude, speed, vertical speed...</td><td>✈️ <a href="https://apify.com/abotapi/viator-com-scraper"><b>Viator Scraper</b></a><br>Collect Viator.com tour and activity results from destinations, categories, search pages...</td></tr>
<tr><td>🏨 <a href="https://apify.com/abotapi/booking-com-scraper"><b>Booking.com Hotels, Prices and Reviews Scraper</b></a><br>Scrape booking.com hotels, apartments, villas and hostels. Search any destination with...</td><td>💼 <a href="https://apify.com/abotapi/f6s-directory-scraper"><b>F6S Scraper</b></a><br>Extract structured data from F6S.com. Scrape funding programs, startup accelerators...</td></tr>
<tr><td>🏨 <a href="https://apify.com/abotapi/vrbo-vacation-rentals-scraper"><b>Vrbo Scraper</b></a><br>Extract vacation rental data from Vrbo.com by location, region, coordinates, property...</td><td>✈️ <a href="https://apify.com/abotapi/pollstar-concert-tour-scraper"><b>Pollstar Scraper</b></a><br>Scrape Pollstar upcoming concerts and tour dates: play date, venue with full address and...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/flightpoints-award-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Choose 'search' to run one route or a bulk list of routes, or 'url' to scrape pasted search links from flightpoints.com/search or roame.travel/search.

## `origin` (type: `string`):

Origin airport: a 3-letter IATA code (e.g. JFK) or an airport / city name (e.g. Heathrow). A name that matches no airport, or several, is reported in the log and that route is skipped. Used with Destination + Departure date for a single-route search.

## `destination` (type: `string`):

Destination airport: a 3-letter IATA code (e.g. LHR) or an airport / city name. A name that matches no airport, or several, is reported in the log and that route is skipped.

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

Departure date as YYYY-MM-DD (within ~60 days forward). Leave blank to use the next ~30 days out.

## `routes` (type: `array`):

Optional. A list of routes to search in one run, overrides the single-route fields above. Each item is an object {"origin":"JFK","destination":"LHR","departureDate":"2026-09-16"} or a CSV-style line "JFK,LHR,2026-09-16". Paste multiple lines for a bulk campaign.

## `sources` (type: `array`):

Which award-search engines to query. Default: both.

## `urls` (type: `array`):

Only used when mode = url. Paste one or more search links. Multiple origins or destinations in one link (origins=JFK,EWR) are expanded to every pair; cabin/class and direct are honoured. Leave untouched to scrape one example per supported link shape.

## `searchClass` (type: `string`):

Cabin class to search on Roame. Flightpoints returns all cabins regardless.

## `daysAround` (type: `integer`):

Widen the search by +/- this many days around the departure date. Flightpoints returns every date in the window; Roame spreads the search across it.

## `directOnly` (type: `boolean`):

Return non-stop itineraries only.

## `startDate` (type: `string`):

Optional. With End date, searches every day in the window (search mode, single route only; capped at 60 days). Overrides Departure date.

## `endDate` (type: `string`):

Optional. Last day of the date window (YYYY-MM-DD). The window is capped at 60 days after the start date.

## `cabin` (type: `string`):

Keep only itineraries with award space in this cabin, for BOTH sources. Leave empty for any cabin.

## `maxMiles` (type: `integer`):

Keep itineraries whose (selected or any) cabin costs at most this many miles.

## `maxCashTaxes` (type: `number`):

Keep itineraries whose (selected or any) cabin has taxes and fees at most this amount.

## `minSeats` (type: `integer`):

Keep itineraries whose (selected or any) cabin has at least this many seats.

## `nonstop` (type: `boolean`):

Alias of Direct flights only; either one turns the filter on.

## `issuers` (type: `array`):

Keep only these loyalty program codes, e.g. CX, AA. Empty = all programs.

## `operatingAirlines` (type: `array`):

Keep itineraries operated by at least one of these airline codes, e.g. BA, VS. Empty = all.

## `sortBy` (type: `string`):

Within each batch of results, list itineraries offering this cabin first, cheapest miles first.

## `maxItems` (type: `integer`):

Maximum number of award itineraries to return across the whole run. This is the run's cap. Use 0 for unlimited.

## `fetchDetails` (type: `boolean`):

Off by default. When on, Flightpoints results also return per-flight detail: departure/arrival times, duration, stops, distance, per-cabin cash prices and seats, the segments that make up each itinerary (with layover times — stopover info) and a booking link. Each enriched itinerary is charged a small surcharge; the base per-itinerary charge still applies.

## `proxy` (type: `object`):

Apify Proxy. The default (datacenter) connection was measured to serve both sources, so no residential tier is required. Apify free plans have no Apify Proxy and fall back to a backup connection; you can also supply your own proxy URLs.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl without returning or charging for itineraries already collected there. Use this after an interrupted run, or when continuing a campaign in another run. For recurring daily monitoring of the same routes, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching itineraries as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED itineraries. UPDATED is decided by comparing every output field except the volatile ones: miles/points, taxes/surcharge, seats, stops, airlines, times and segments all count, while the source's last-seen/update timestamps, the scrape time and the derived Roame score and premium ratio never do (they stay in the output but never trigger UPDATED or changedFields, including inside cabins and segments). Turn on "Emit unchanged" or "Emit expired" only when you also want those itineraries returned (and billed). State is kept separately for each route/URL and detail-mode setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the routes/URLs and detail settings — different routes then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return itineraries that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return itineraries that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked routes — not when Max itineraries capped it or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## `ignoreFieldsForChanges` (type: `array`):

Field names that must NOT make an itinerary count as UPDATED, in addition to the built-in volatile fields. A bare name such as seats matches at any depth (top level, cabins, segments); a dotted path such as cabins.economy.seats matches only that field. The field stays in the output. Only used when Incremental changes is on. Example: \["seats", "surcharge"] to track miles only.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "origin": "JFK",
  "destination": "LHR",
  "departureDate": "",
  "sources": [
    "flightpoints",
    "roame"
  ],
  "urls": [
    "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16",
    "https://www.flightpoints.com/search?origins=JFK,EWR&destinations=LHR&date=2026-11-16",
    "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16&cabin=business&direct=true",
    "http://flightpoints.com/search?origins=JFK&destinations=LHR",
    "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16",
    "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16&searchClass=BUS",
    "https://roame.travel/search?origin=JFK&destination=LHR&date=2026-11-16",
    "https://flightpoints.com/search"
  ],
  "searchClass": "ECON",
  "daysAround": 0,
  "directOnly": false,
  "cabin": "",
  "nonstop": false,
  "sortBy": "",
  "maxItems": 20,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `segments` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "mode": "search",
    "origin": "JFK",
    "destination": "LHR",
    "departureDate": "",
    "sources": [
        "flightpoints",
        "roame"
    ],
    "urls": [
        "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16",
        "https://www.flightpoints.com/search?origins=JFK,EWR&destinations=LHR&date=2026-11-16",
        "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16&cabin=business&direct=true",
        "http://flightpoints.com/search?origins=JFK&destinations=LHR",
        "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16",
        "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16&searchClass=BUS",
        "https://roame.travel/search?origin=JFK&destination=LHR&date=2026-11-16",
        "https://flightpoints.com/search"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/flightpoints-award-scraper").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 = {
    "mode": "search",
    "origin": "JFK",
    "destination": "LHR",
    "departureDate": "",
    "sources": [
        "flightpoints",
        "roame",
    ],
    "urls": [
        "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16",
        "https://www.flightpoints.com/search?origins=JFK,EWR&destinations=LHR&date=2026-11-16",
        "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16&cabin=business&direct=true",
        "http://flightpoints.com/search?origins=JFK&destinations=LHR",
        "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16",
        "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16&searchClass=BUS",
        "https://roame.travel/search?origin=JFK&destination=LHR&date=2026-11-16",
        "https://flightpoints.com/search",
    ],
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/flightpoints-award-scraper").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 '{
  "mode": "search",
  "origin": "JFK",
  "destination": "LHR",
  "departureDate": "",
  "sources": [
    "flightpoints",
    "roame"
  ],
  "urls": [
    "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16",
    "https://www.flightpoints.com/search?origins=JFK,EWR&destinations=LHR&date=2026-11-16",
    "https://flightpoints.com/search?origins=JFK&destinations=LHR&date=2026-11-16&cabin=business&direct=true",
    "http://flightpoints.com/search?origins=JFK&destinations=LHR",
    "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16",
    "https://roame.travel/search?from=JFK&to=LHR&departureDate=2026-11-16&searchClass=BUS",
    "https://roame.travel/search?origin=JFK&destination=LHR&date=2026-11-16",
    "https://flightpoints.com/search"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/flightpoints-award-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/flightpoints-award-scraper"
        }
    }
}
```

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/Rp0Oehz58p0885ama/builds/FTAJ3cyQ96Sq5XRwR/openapi.json
