{
  "openapi": "3.0.1",
  "info": {
    "title": "Flight Price Aggregator API 💰 — 7 Sources, One Query",
    "description": "Compare flight prices across Google Flights, Skyscanner, Kiwi, Ryanair, Wizz Air, EasyJet & Norwegian in one call — or batch 50 routes per run. Merges the same flight across sources and converts every currency to yours, so the cheapest tag is real. Optional per-route savings summary. JSON/CSV.",
    "version": "0.0",
    "x-build-id": "4WBp0r02Y83uVUtL6"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/memo23~flights-aggregator-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-memo23-flights-aggregator-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/memo23~flights-aggregator-scraper/runs": {
      "post": {
        "operationId": "runs-sync-memo23-flights-aggregator-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/memo23~flights-aggregator-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-memo23-flights-aggregator-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "origin": {
            "title": "Origin (city or airport)",
            "type": "string",
            "description": "Origin as a city name (e.g. London, Barcelona) or an airport IATA code (e.g. LHR, JFK). A city resolves to its primary airport — pass an exact IATA to target another (e.g. STN)."
          },
          "destination": {
            "title": "Destination (city or airport)",
            "type": "string",
            "description": "Destination as a city name (e.g. Barcelona) or an airport IATA code (e.g. BCN, CDG)."
          },
          "departDate": {
            "title": "Departure date",
            "type": "string",
            "description": "Outbound date, format YYYY-MM-DD. Leave empty to default to ~30 days from today — a bare run always searches bookable dates (past dates are bumped forward too)."
          },
          "returnDate": {
            "title": "Return date (optional)",
            "type": "string",
            "description": "Return date for a round trip. Leave empty for one-way."
          },
          "adults": {
            "title": "Adults",
            "minimum": 1,
            "maximum": 9,
            "type": "integer",
            "description": "Number of adult passengers.",
            "default": 1
          },
          "children": {
            "title": "Children",
            "minimum": 0,
            "maximum": 9,
            "type": "integer",
            "description": "Number of child passengers.",
            "default": 0
          },
          "currency": {
            "title": "Currency",
            "type": "string",
            "description": "Currency for price comparison (ISO 4217, e.g. USD, GBP, EUR). Sources that accept a currency are queried in it. Wizz Air and easyJet always price in the departure market's currency — those rows keep the price they actually quote in \"price\"/\"currency\", and also carry \"priceNormalized\" in this currency (ECB daily reference rates, plus a backup feed for the currencies the ECB doesn't publish — Wizz Air's ALL/RSD/MKD/BAM/GEL/MDL/UAH/AED markets) so the cheapest tag and the route summary compare like for like.",
            "default": "USD"
          },
          "cabinClass": {
            "title": "Cabin class",
            "enum": [
              "ECONOMY",
              "PREMIUM_ECONOMY",
              "BUSINESS",
              "FIRST"
            ],
            "type": "string",
            "description": "Preferred cabin class.",
            "default": "ECONOMY"
          },
          "routes": {
            "title": "Routes (batch mode)",
            "type": "array",
            "description": "Optional batch mode: search many routes in ONE run. Array of objects — each needs \"origin\" and \"destination\" (city name or IATA); \"departDate\"/\"returnDate\" are optional per route and fall back to the top-level dates. When set, the top-level origin/destination are ignored. Max 50 routes per run. Example: [{\"origin\":\"LHR\",\"destination\":\"BCN\"},{\"origin\":\"LHR\",\"destination\":\"MAD\",\"departDate\":\"2026-09-01\"}]"
          },
          "directOnly": {
            "title": "Direct flights only",
            "type": "boolean",
            "description": "Only keep nonstop flights (stops = 0). Applies to the sources that return a per-flight schedule (Google Flights, Skyscanner, Kiwi, Ryanair), connections included. The date-calendar sources (easyJet, Wizz Air, Norwegian) quote one cheapest fare per day with no flight times, so they cannot answer a stop question and are skipped while this or any other stop/duration filter is on.",
            "default": false
          },
          "maxStops": {
            "title": "Max stops",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Only keep flights with at most this many stops (0 = nonstop). Leave empty for no limit. Values of 1 or more return real connections from Skyscanner and Kiwi alongside the nonstop results. The date-calendar sources (easyJet, Wizz Air, Norwegian) are skipped while this filter is on — they quote one cheapest fare per day and cannot say how many stops it has."
          },
          "maxDurationMinutes": {
            "title": "Max total duration (minutes)",
            "minimum": 30,
            "type": "integer",
            "description": "Only keep flights whose total duration is at most this many minutes (e.g. 300 = 5h), measured gate to gate including layovers. Leave empty for no limit. The date-calendar sources (easyJet, Wizz Air, Norwegian) publish no durations and are skipped while this filter is on."
          },
          "includeRouteSummary": {
            "title": "Include route summary",
            "type": "boolean",
            "description": "Emit one cross-source comparison row per route into a separate \"route-summaries\" dataset: cheapest price and source per direction, the spread between the cheapest and most expensive source (what you save by booking the right one), every source's price, plus which sources answered, failed, or timed out. Kept out of the main dataset so your flight rows and CSV columns stay unchanged.",
            "default": false
          },
          "routeSummaryDatasetName": {
            "title": "Route summary dataset name",
            "type": "string",
            "description": "Where the route-summary rows go. Named datasets are per-account and append-only, so summaries from every run accumulate in one place — which is exactly what makes a scheduled fare watch readable as price history. Override it to keep separate watchlists, clients or environments apart. Only used when \"Include route summary\" is on.",
            "default": "route-summaries"
          },
          "sources": {
            "title": "Sources to query",
            "type": "array",
            "description": "Which flight sources to fan out to. Leave empty to query all seven. Note: Ryanair, Wizz Air, EasyJet and Norwegian only fly their own (mostly European) routes.",
            "items": {
              "type": "string",
              "enum": [
                "ryanair",
                "wizzair",
                "easyjet",
                "norwegian",
                "googleflights",
                "skyscanner",
                "kiwi"
              ]
            },
            "default": []
          },
          "maxPerSource": {
            "title": "Max offers per source",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "Cap on the number of offers returned by each source before merging. Connecting itineraries are capped again after merging — see \"Max connecting itineraries per source\", which is the setting that decides how many of them you are billed for.",
            "default": 10
          },
          "maxConnectionsPerSource": {
            "title": "Max connecting itineraries per source",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "How many CONNECTING itineraries each source may return, per direction, airport pair and date. A connection has no single flight number, so it cannot be price-matched against other sources — every one is its own row, and every row is one billed item. 3 (the default) returns the three cheapest per source; 1 returns only the cheapest; raise it up to \"Max offers per source\" for the full set. This governs Skyscanner and Kiwi connections. It does not apply to nonstop flights (they merge across sources on their flight number), and it does not apply to the per-date cheapest fares from easyJet, Wizz Air and Norwegian — those already return at most one row per airport pair, and on a multi-airport city easyJet returns one row per airport it actually serves (searching London Heathrow returns Gatwick, Luton, Stansted and Southend), which no setting here changes.",
            "default": 3
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Optional. Skyscanner and Google Flights run through a built-in egress pool and need nothing here. Norwegian works best from an Apify RESIDENTIAL IP — select it if your account has it. Left empty, the actor uses its built-in pool and Norwegian falls back to that (it may be blocked). There is no forced default on purpose: a proxy setting your account cannot use (a named group you lack, or automatic mode when your proxy allowance is spent) fails the run at input validation before it starts."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}