{
  "openapi": "3.0.1",
  "info": {
    "title": "Booking.com Scraper — Hotel Prices & Availability by Date",
    "description": "Booking.com prices and availability by date for destinations or hotels by URL, name or id. One row per hotel: stay total, nightly rate, taxes, free cancellation, breakfast, stars, review score, sold out. Optional room rates. Filters before billing: max price, star class. Price tracking, comp sets.",
    "version": "1.2",
    "x-build-id": "KDIWqvwmW1B47bYlx"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/kestrel~booking-prices-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-kestrel-booking-prices-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/kestrel~booking-prices-scraper/runs": {
      "post": {
        "operationId": "runs-sync-kestrel-booking-prices-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/kestrel~booking-prices-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-kestrel-booking-prices-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": {
          "locationQueries": {
            "title": "Destinations",
            "type": "array",
            "description": "Places as typed into Booking.com's search box, e.g. [\"Lisbon\"], [\"Algarve\"], [\"Portugal\"]: a city, region, district, landmark, airport or country, resolved through Booking's own autocomplete. Each becomes one search for the stay, returning up to maxHotelsPerQuery properties in sortBy order. Add the country for ambiguous names (\"Barcelona, Spain\"). An unmatched place is a free status row, nothing charged. Empty = price only the hotels named below. Use for \"hotel prices in Lisbon next weekend\".",
            "items": {
              "type": "string"
            }
          },
          "hotelNames": {
            "title": "Hotel names",
            "type": "array",
            "description": "Property names as typed into Booking's search box, e.g. [\"Memmo Alfama Lisbon\", \"Hotel Artemide Rome\"]: add the city. Booking's autocomplete picks the first matching property; check hotel_name in the free status row. A name that matches nothing costs nothing. Each name is priced on its own for the stay: sortBy, maxHotelsPerQuery and minStars do not apply to named hotels, maxPrice does. Use for \"what does hotel X cost on these dates\" and for comp sets.",
            "items": {
              "type": "string"
            }
          },
          "hotelIds": {
            "title": "Hotel ids",
            "type": "array",
            "description": "Booking.com numeric property ids, e.g. [\"536251\", \"2251985\"]: the hotel_id column of an earlier run. The fastest way to re-price the same hotels every day (a comp set, a portfolio): one small request per hotel, no name lookup. Use with a relative checkIn (\"30 days\") on an Apify schedule for price tracking. An id Booking does not know is a free status row (not_found). A hotel given twice, or reached by a destination search too, is delivered and billed once.",
            "items": {
              "type": "string"
            }
          },
          "startUrls": {
            "title": "Hotel URLs",
            "type": "array",
            "description": "Booking.com property pages, e.g. [\"https://www.booking.com/hotel/pt/memmo-alfama.html\"]. A URL carries no id, so its slug is resolved through Booking's autocomplete first (the country code must match), then the hotel is priced on its own for the stay. Search pages and other sites are refused before anything is charged. Prefer hotelIds when you have them.",
            "items": {
              "type": "string"
            }
          },
          "checkIn": {
            "title": "Check-in",
            "type": "string",
            "description": "REQUIRED (no default): check-in date as \"2026-11-20\" (YYYY-MM-DD) or relative to the day the run starts: \"30 days\", \"6 weeks\", \"tomorrow\". Use relative dates for scheduled runs (\"track prices daily at a 30-day lead time\"): the input never goes stale. Check-out = checkIn + nights. A past date is refused before anything is charged."
          },
          "nights": {
            "title": "Nights",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Length of stay, 1 to 30, e.g. 2 (default 1). price_total is for the whole stay; price_nightly = price_total ÷ nights. Rows from runs with the same nights, adults and rooms line up as a price history.",
            "default": 1
          },
          "adults": {
            "title": "Adults",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Adults across all rooms, 1 to 30, e.g. 2 (default 2). Booking prices the party you ask for: a solo traveller and a couple can see different rates for the same room.",
            "default": 2
          },
          "childrenAges": {
            "title": "Children's ages",
            "type": "array",
            "description": "One age per child, 0 to 17, e.g. [\"5\", \"9\"] for two children aged 5 and 9. Empty (default) = no children. Booking needs ages, not a count, to match family rooms and child policies; the stay total covers the whole party.",
            "items": {
              "type": "string"
            }
          },
          "rooms": {
            "title": "Rooms",
            "minimum": 1,
            "maximum": 30,
            "type": "integer",
            "description": "Rooms the party needs, 1 to 30, e.g. 1 (default 1). With 2 rooms Booking matches two room blocks per property and price_total covers both.",
            "default": 1
          },
          "currency": {
            "title": "Currency",
            "type": "string",
            "description": "ISO 4217 code for every price, e.g. \"EUR\" (default \"USD\"). When the user names no currency, pass the destination's (\"GBP\" for London). The hotel's own currency stays alongside in hotel_currency and price_hotel_currency_total, so conversions are yours to make.",
            "default": "USD"
          },
          "maxHotelsPerQuery": {
            "title": "Max properties per destination",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Properties to return per destination search, 1 to 1000, e.g. 100 (default 50). The main cost control: at most maxHotelsPerQuery × $0.004 per destination, plus room rows when includeRooms is true. Taken in sortBy order after Booking's minStars filter; maxPrice then drops rows above the cap, so 50 asked with maxPrice set can deliver fewer. Booking pages 100 at a time: 100 = one request, 1000 = ten. Not applied to named hotels.",
            "default": 50
          },
          "sortBy": {
            "title": "Sort destination results by",
            "enum": [
              "popularity",
              "price",
              "price_desc",
              "review_score",
              "review_score_and_price",
              "stars",
              "stars_asc",
              "stars_and_price",
              "distance",
              "homes_first"
            ],
            "type": "string",
            "description": "Booking's own order for destination searches: \"popularity\" (default: Booking's personalised top picks, which shift between pages), \"price\" (cheapest first), \"price_desc\", \"review_score\", \"review_score_and_price\", \"stars\", \"stars_asc\", \"stars_and_price\", \"distance\" (from the centre), \"homes_first\". Use \"price\" with maxHotelsPerQuery for \"the 50 cheapest hotels in Lisbon\"; use price, review_score, stars or distance for repeatable daily runs. The rank column follows this order.",
            "default": "popularity"
          },
          "maxPrice": {
            "title": "Max nightly price",
            "minimum": 0,
            "type": "number",
            "description": "Highest nightly price in `currency`, e.g. 150. 0 (default) = no cap. Keeps properties whose price_nightly (stay total ÷ nights, the displayed total, which in some markets excludes taxes) is at or under it; dropped properties are never delivered or billed, so a daily \"anything under 150\" alert costs nothing on days without a match. With a cap set, sold-out properties are dropped too (no price to compare). Applies to destination searches and named hotels. Use for \"hotels under 150 EUR a night\".",
            "default": 0
          },
          "minStars": {
            "title": "Minimum stars",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Booking's own star filter, 0 to 5, e.g. 4: sent to Booking as its class=N search filter (what the site sends when a star class is ticked), so filtered properties are never fetched or billed. 0 (default) = no star filter. Read the stars column of the rows that come back: with 4 Booking returns the properties its 4-star filter matches, and unrated apartments and hostels have no stars. Destination searches only; named hotels are always priced.",
            "default": 0
          },
          "includeRooms": {
            "title": "Room-level rates",
            "type": "boolean",
            "description": "false (DEFAULT) = one hotel row per property, carrying the cheapest room's name only. true = also one room row per room and rate combination Booking matched to the stay, at $0.002 each: room name, occupancy, meal plan, stay total and nightly rate, free-cancellation deadline, \"only X left\". The hotel row's rooms_listed is the number of room rows to expect. Keep false for price tracking and market scans; true for \"every room and rate hotel X offers\", meal plans or cancellation deadlines.",
            "default": false
          },
          "locale": {
            "title": "Locale",
            "type": "string",
            "description": "Booking locale for the request, e.g. \"en-US\" (default), \"en-GB\", \"de-DE\", \"fr-FR\", \"pt-PT\", \"ja-JP\". Sets the language of labels (meal plan, distance texts, sold-out message, charges note) and the number format of price_display. Prices are set by currency, not by locale.",
            "default": "en-US"
          },
          "sessions": {
            "title": "Proxy sessions",
            "minimum": 1,
            "maximum": 16,
            "type": "integer",
            "description": "Parallel proxy sessions (egress IPs), 1 to 16, e.g. 4 (default 4). More is faster; each session is paced separately by perIp. Leave the default unless Booking refuses requests.",
            "default": 4
          },
          "perIp": {
            "title": "Requests per second per session",
            "minimum": 0.1,
            "maximum": 3,
            "type": "number",
            "description": "Requests per second per session, 0.1 to 3, e.g. 1 (default 1). Booking answered 10 searches at 1/s from one IP without refusals, and a search takes 2 to 4 s anyway, so raising it rarely helps.",
            "default": 1
          },
          "proxyConfiguration": {
            "title": "Proxy",
            "type": "object",
            "description": "Apify Proxy with the RESIDENTIAL group (default) is required: Booking's search call answers datacenter IPs with its WAF challenge and residential IPs without cookies or tokens. Keep the default; a datacenter group makes every search fail (nothing charged).",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}