{
  "openapi": "3.0.1",
  "info": {
    "title": "Airbnb Scraper: Listings, Prices, Fees, Calendar & Reviews",
    "description": "Scrape Airbnb listings by location, map area, search URL or listing URL. Exact stay prices as numbers with breakdown, host ratings, permit numbers, availability calendar, occupancy estimates and reviews.",
    "version": "0.1",
    "x-build-id": "dmhNWxGhsrib2pYAi"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/thelastscraper~airbnb-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-thelastscraper-airbnb-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/thelastscraper~airbnb-scraper/runs": {
      "post": {
        "operationId": "runs-sync-thelastscraper-airbnb-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/thelastscraper~airbnb-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-thelastscraper-airbnb-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": {
          "where": {
            "title": "Where: neighborhoods, cities, Airbnb URLs or listing IDs",
            "type": "array",
            "description": "One per line. A place as you would type it on Airbnb (\"Dubai Marina, Dubai\", \"Lisbon, Portugal\"), an Airbnb search URL (its filters are kept, including its guests and dates; dates set here replace its dates, the currency always comes from this form), a listing URL (https://www.airbnb.com/rooms/123) or a listing ID. The Actor detects which is which. Places are resolved with their real OpenStreetMap boundary, so repeated runs cover exactly the same area. To search a postal code, add the city (\"10001, New York\").",
            "items": {
              "type": "string"
            }
          },
          "checkIn": {
            "title": "Check-in date",
            "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$",
            "type": "string",
            "description": "YYYY-MM-DD. Leave both dates empty for automatic dates (30 days from today, 5 nights): Airbnb only quotes a price for specific dates. Note: a search with dates only returns the homes still free on those nights. This form starts with 'Which listings' = Only listings available on your dates, so every listing has a price; for market analysis, occupancy or leads switch it to All active listings."
          },
          "checkOut": {
            "title": "Check-out date",
            "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$",
            "type": "string",
            "description": "YYYY-MM-DD, after the check-in date. Empty with an empty check-in = automatic dates (each record says so in scrape.dates_auto)."
          },
          "adults": {
            "title": "Adults",
            "minimum": 0,
            "maximum": 16,
            "type": "integer",
            "description": "Adult guests. Airbnb keeps the listings that accommodate at least this many people (4 also brings listings for 5, 6 or more guests) and quotes each price for exactly this party. 0 = any number of guests: no capacity filter, each price quoted for one guest (cannot be combined with Children).",
            "default": 2
          },
          "children": {
            "title": "Children",
            "minimum": 0,
            "maximum": 15,
            "type": "integer",
            "description": "Ages 2-12. They count toward the listing's capacity like adults and pay the extra-guest fee in the quote.",
            "default": 0
          },
          "infants": {
            "title": "Infants",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Under 2. They do not count toward capacity and stay free.",
            "default": 0
          },
          "pets": {
            "title": "Pets",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Only pet-friendly listings are returned, and the quote includes the host's pet fee (folded into the nightly rate).",
            "default": 0
          },
          "dataLevel": {
            "title": "Level of detail",
            "enum": [
              "estimate",
              "snapshot",
              "details",
              "revenue",
              "everything",
              "leads"
            ],
            "type": "string",
            "description": "Estimate: counts the listings in the area and tells you what each level would cost, nothing charged. Snapshot: search card per listing: price for your dates, rating, capacity, location, photos (~$1.00 per 1,000 listings on the Free plan, $0.25 on Gold). Details: + full listing page: price breakdown, cancellation policy, host, amenities, house rules, permit number (~$2.50 / $0.95). Revenue & occupancy: + 12-month availability calendar with occupancy and revenue estimates (~$3.50 / $1.45). Everything: + all guest reviews (+$0.50 per 1,000 reviews; $0.25 on Gold) and a 13-month calendar. Find management leads (for property managers): Revenue & occupancy plus the newest reviews (read for the score, not charged), every listing found (with 'Which listings' = All active listings, the whole area) scored on how much it underperforms the area and whether its owner can still be won, ranked best first, with a LEADS table in the key-value store (~$3.50 / $1.45). Listings given by URL or ID always get at least Details.",
            "default": "details"
          },
          "coverage": {
            "title": "Which listings",
            "enum": [
              "all",
              "available"
            ],
            "type": "string",
            "description": "All listings (the default for Details, Revenue, Everything and Find management leads when this field is empty): the Actor searches without dates to find every active listing in the area, then quotes each one for your dates. Booked listings are included with price.is_available = false and no price, so prices and occupancy are not biased toward the homes nobody booked; with a small Max listings most of them can be booked (the run's status says how many). Only available (the default for Snapshot, and what this form starts with, so a first run shows prices): a search with your dates, which returns only the homes still free on those nights. For market analysis choose All listings. All listings means more listings per area, and therefore a higher cost: run an Estimate first, it shows both counts."
          },
          "photos": {
            "title": "Photos",
            "enum": [
              "full",
              "preview",
              "none"
            ],
            "type": "string",
            "description": "Photo URLs in each listing (the Actor never downloads image files). Full gallery: every photo; when Airbnb sends a listing with only its first 5 photos (common for regular homes at busy times), the Actor also reads the listing's web page: one more request and about 0.5-0.9 MB per such listing, so runs take longer. Preview: the photos Airbnb sends (up to 5 plus the cover when it trims the gallery; photo_count is then empty and photos_complete false), faster. None: no photo list (the cover photo stays). The price is the same either way. Empty = Preview for Snapshot, Details and Revenue & occupancy; Full gallery for Everything and Find management leads (the lead score uses the number of photos)."
          },
          "marketReport": {
            "title": "Market report (HTML)",
            "enum": [
              "auto",
              "on",
              "off"
            ],
            "type": "string",
            "description": "A ready-to-share HTML report of the listings in this run, saved as MARKET_REPORT in the key-value store: prices by bedrooms and building, occupancy, demand, quality, hosts, amenities, policies, permits and a price map, with the methodology. $0.50 per run, charged only if the report is created. Auto = on for Revenue & occupancy, Everything and Find management leads (except when Monitoring), off for Snapshot and Details.",
            "default": "auto"
          },
          "maxListings": {
            "title": "Max listings",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after this many unique listings across all places and URLs (after filters). 0 = no limit. The default (200) costs about $0.50 at Details on the Free plan; if the area has more listings, the run says how many and what all of them would cost. Start small, or run an Estimate first, to check the data and the cost. To track a market (Monitoring), use 0: the whole area has to be searched to notice listings that disappear.",
            "default": 200
          },
          "currency": {
            "title": "Currency",
            "pattern": "^[A-Z]{3}$",
            "type": "string",
            "description": "ISO 4217 code (default USD). All amounts are returned as numbers in this currency; it also replaces the currency of an Airbnb search URL.",
            "default": "USD"
          },
          "outputFormat": {
            "title": "Output format",
            "enum": [
              "spreadsheet",
              "full_json"
            ],
            "type": "string",
            "description": "Spreadsheet (default): one flat row per listing with 98 curated columns (100 with a language) in a useful order (url first, listing_id as text, prices as numbers, key amenities as true/false, estimates prefixed est_), ready for Excel, Google Sheets or CSV. Full JSON: the complete nested record of every listing (~2,800 fields once flattened: line items, every amenity and photo, description, field sources), for developers. Reviews and calendar days are the same in both.",
            "default": "spreadsheet"
          },
          "language": {
            "title": "Language of the texts",
            "enum": [
              "en",
              "sq",
              "ar",
              "hy",
              "az",
              "bs",
              "bg",
              "ca",
              "zh-HK",
              "zh",
              "zh-TW",
              "hr",
              "cs",
              "da",
              "nl",
              "nl-BE",
              "en-AU",
              "en-CA",
              "en-GB",
              "et",
              "fi",
              "fr",
              "fr-CA",
              "ka",
              "de",
              "el",
              "he",
              "hi",
              "hu",
              "is",
              "id",
              "ga",
              "it",
              "ja",
              "kn",
              "ko",
              "lv",
              "lt",
              "mk",
              "ms",
              "mt",
              "mr",
              "sr-ME",
              "no",
              "pl",
              "pt",
              "pt-BR",
              "pt-PT",
              "ro",
              "ru",
              "sr",
              "sk",
              "sl",
              "es",
              "es-AR",
              "es-XL",
              "es-419",
              "sw",
              "sv",
              "tl",
              "th",
              "tr",
              "uk",
              "vi",
              "xh",
              "zu"
            ],
            "type": "string",
            "description": "Everything is collected and parsed in English. Another language adds one more listing page per listing (~28 KB, no extra charge) and fills the `localized` block: title, description, amenities and house rules in that language (Airbnb's machine translation when the host wrote in another one; the originals stay in the main fields). In Spreadsheet output, the columns title_localized and description_localized. Needs the listing page (Details or higher). Reviews stay in their original language.",
            "default": "en"
          },
          "bedroomsExact": {
            "title": "Exactly N bedrooms",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only listings with exactly this many bedrooms. Airbnb only filters by minimum, so the Actor asks Airbnb for at least this many and checks the exact number on each search card or, when the card does not show it (in Europe a search without dates shows the host type there instead), on the listing page. Listings that do not match are not delivered or charged."
          },
          "minBedrooms": {
            "title": "Min bedrooms",
            "minimum": 0,
            "type": "integer",
            "description": "Airbnb's own filter (\"N or more\")."
          },
          "minBathrooms": {
            "title": "Min bathrooms",
            "minimum": 0,
            "type": "number",
            "description": "Airbnb's own filter (\"N or more\"); half bathrooms count as 0.5."
          },
          "minBeds": {
            "title": "Min beds",
            "minimum": 0,
            "type": "integer",
            "description": "Airbnb's own filter (\"N or more\")."
          },
          "roomTypes": {
            "title": "Type of place",
            "type": "array",
            "description": "Leave empty for any type.",
            "items": {
              "type": "string",
              "enum": [
                "Entire home/apt",
                "Private room",
                "Shared room",
                "Hotel room"
              ],
              "enumTitles": [
                "Entire home / apartment",
                "Private room",
                "Shared room",
                "Hotel room"
              ]
            }
          },
          "propertyTypes": {
            "title": "Property types",
            "type": "array",
            "description": "Keep only these property types, e.g. \"apartment\", \"villa\", \"townhouse\", \"serviced apartment\", \"condo\". Case-insensitive partial match against the listing's property type (\"apartment\" also matches \"serviced apartment\"). Empty = any. Checked on the search card when it says the type, otherwise on the listing page.",
            "items": {
              "type": "string"
            }
          },
          "amenities": {
            "title": "Amenities",
            "type": "array",
            "description": "Keep only listings with ALL the amenities picked (Airbnb's own filter). With listing URLs or IDs the Actor checks them on the listing page; what the page cannot confirm is kept with a FILTER_UNVERIFIED warning. Amenity ids of other markets work inside an Airbnb search URL (amenities[]=...).",
            "items": {
              "type": "string",
              "enum": [
                "Wifi",
                "Air conditioning",
                "Pool",
                "Kitchen",
                "Free parking",
                "Smoking allowed",
                "Gym",
                "Breakfast",
                "Hot tub",
                "Indoor fireplace",
                "Heating",
                "Washer",
                "Dryer",
                "Smoke alarm",
                "Carbon monoxide alarm",
                "Hair dryer",
                "Iron",
                "Dedicated workspace",
                "Self check-in",
                "TV",
                "EV charger",
                "BBQ grill",
                "Step-free access",
                "Guest entrance wider than 32 inches",
                "Disabled parking spot",
                "Step-free bedroom access",
                "Bedroom entrance wider than 32 inches",
                "Step-free bathroom access",
                "Bathroom entrance wider than 32 inches",
                "Crib",
                "Ceiling or mobile hoist",
                "Shower grab bar",
                "Toilet grab bar",
                "Step-free shower",
                "Shower or bath chair",
                "King bed"
              ]
            }
          },
          "priceMin": {
            "title": "Min price",
            "minimum": 0,
            "type": "integer",
            "description": "Price per night, in the selected currency. With 'Only listings available on your dates' it is Airbnb's own search filter. With 'All active listings' the Actor applies it to each listing's exact quote for your dates (price.price_per_night: total including fees and taxes, divided by the nights); booked listings have no price and are kept unless 'Only available on my dates' is on."
          },
          "priceMax": {
            "title": "Max price",
            "minimum": 0,
            "type": "integer",
            "description": "Price per night, in the selected currency. Applied like Min price."
          },
          "onlyAvailable": {
            "title": "Only available on my dates",
            "type": "boolean",
            "description": "With 'All active listings': deliver only the listings whose quote for your dates says available (booked listings, and the few whose quote failed, are dropped and never charged). It still finds them through the search without dates, so the area is fully covered. Needs dates and a level with the listing page (Details or higher).",
            "default": false
          },
          "freeCancellation": {
            "title": "Free cancellation only",
            "type": "boolean",
            "description": "Keep only listings with free cancellation for your dates (Airbnb's own filter; with listing URLs or IDs, checked on the cancellation policy).",
            "default": false
          },
          "minRating": {
            "title": "Minimum rating",
            "minimum": 0,
            "maximum": 5,
            "type": "number",
            "description": "Keep only listings rated at least this much (e.g. 4.8). Listings without a rating yet are dropped. Empty = no filter. Checked on the search card, so dropped listings cost nothing."
          },
          "superhostOnly": {
            "title": "Superhosts only",
            "type": "boolean",
            "description": "Keep only listings whose host is a Superhost. With Details or higher it is checked on the listing page; with Snapshot only listings whose search card shows the Superhost badge are kept.",
            "default": false
          },
          "monitorName": {
            "title": "Track this market (monitor name)",
            "type": "string",
            "description": "Any name, e.g. \"Dubai Marina 2BR\". Runs with the same name share one monitor, saved in a named key-value store of your account (airbnb-monitor-<name in lowercase with hyphens>). Empty = no monitoring. Set fixed check-in/check-out dates to track price changes (automatic dates move every day, so totals are not comparable). Monitoring reads the calendar (that is how bookings show up), so Details runs are priced as Revenue & occupancy. With Snapshot only the search card is compared (price shown, rating, review count): no bookings, no reviews."
          },
          "monitorTiers": {
            "title": "Monitoring depth",
            "enum": [
              "light",
              "full"
            ],
            "type": "string",
            "description": "Light (default): each run reads the search card, the price quote and the calendar; the full listing page only for new listings and every few days (below). Full: the whole level on every run (more requests, same price).",
            "default": "light"
          },
          "monitorFullEveryDays": {
            "title": "Full listing page every (days)",
            "minimum": 0,
            "type": "integer",
            "description": "With Light: refresh the full listing page (amenities, rules, permit, photos) when the last one is older than this.",
            "default": 7
          },
          "monitorDelistAfter": {
            "title": "Removed after N absences",
            "minimum": 1,
            "type": "integer",
            "description": "A listing missing from N runs in a row (searches that covered the whole area) is reported as delisted. Airbnb reshuffles search results, so one absence is not a removal.",
            "default": 3
          },
          "monitorVerifyMissing": {
            "title": "Verify missing listings",
            "type": "boolean",
            "description": "Open the page of each missing listing (1 request each) to confirm whether it was removed or is just out of the search.",
            "default": false
          },
          "monitorReset": {
            "title": "Start the monitor over",
            "type": "boolean",
            "description": "Only if the run fails because the saved monitor state cannot be read: start a new baseline (the unreadable state is kept as STATE_CORRUPT in the monitor's key-value store). Listings already paid for in this monitor are not charged full price again, only as updates.",
            "default": false
          },
          "areaFilter": {
            "title": "Area filter (places)",
            "enum": [
              "polygon",
              "bbox",
              "none"
            ],
            "type": "string",
            "description": "For locations: drop listings outside the place's OpenStreetMap boundary (polygon), outside its bounding box (bbox), or keep everything Airbnb returns (none). Every listing gets location.inside_search_area either way.",
            "default": "polygon"
          },
          "polygonBufferMeters": {
            "title": "Boundary tolerance",
            "minimum": 0,
            "maximum": 3000,
            "type": "integer",
            "description": "Airbnb blurs coordinates by a few hundred meters. A buffer keeps border listings that would be dropped, at the cost of letting in some neighbors.",
            "default": 0
          },
          "pointRadiusMeters": {
            "title": "Radius when the location is a point",
            "minimum": 100,
            "maximum": 20000,
            "type": "integer",
            "description": "If the location resolves to a single point (a building or an address) instead of an area, search this radius around it. The run report says when this happened.",
            "default": 1500
          },
          "locations": {
            "title": "Places (old field)",
            "type": "array",
            "description": "Same as typing places in 'Where'. Kept for runs and integrations made before 'Where' existed; both lists are combined.",
            "items": {
              "type": "string"
            }
          },
          "bbox": {
            "title": "Map area (bounding box)",
            "type": "object",
            "description": "Search only inside this rectangle, like moving Airbnb's map. Object with neLat, neLng, swLat, swLng, e.g. {\"neLat\": 25.09997, \"neLng\": 55.154318, \"swLat\": 25.08042, \"swLng\": 55.136914}. Combined with 'Where'."
          },
          "startUrls": {
            "title": "Airbnb URLs (old field)",
            "type": "array",
            "description": "Airbnb search URLs and/or listing URLs, as before 'Where' existed. Combined with 'Where'.",
            "items": {
              "type": "object",
              "required": [
                "url"
              ],
              "properties": {
                "url": {
                  "type": "string",
                  "title": "URL of a web page",
                  "format": "uri"
                }
              }
            }
          },
          "listingIds": {
            "title": "Listing IDs (old field)",
            "type": "array",
            "description": "Numeric Airbnb listing IDs (or /rooms/ URLs). Combined with 'Where'.",
            "items": {
              "type": "string"
            }
          },
          "mode": {
            "title": "Engine mode (overrides Level of detail)",
            "enum": [
              "search",
              "details",
              "calendar",
              "reviews",
              "full"
            ],
            "type": "string",
            "description": "The engine modes from before 'Level of detail' existed. Leave empty to use the level. Search = Snapshot, Details = Details, Calendar = Revenue (13-month calendar), Full = Everything (4 review pages unless Max review pages says otherwise). Reviews = details + reviews without calendar, which has no level of its own."
          },
          "noDates": {
            "title": "Search without dates",
            "type": "boolean",
            "description": "Search without dates and quote nothing: Airbnb returns every listing in the area, but each card's price is for dates Airbnb picks per listing (price.quote_source = search_no_dates), so prices are not comparable. Usually you want 'Which listings' = All active listings instead, which also finds every listing but quotes each one for your dates. Conflicts with check-in/check-out.",
            "default": false
          },
          "calendarMonths": {
            "title": "Calendar months",
            "minimum": 1,
            "maximum": 24,
            "type": "integer",
            "description": "Months of availability to fetch, starting this month. Empty = 12 for Revenue & occupancy and Find management leads (one request: the 30/60/90-day windows are complete, the 365-day window stays empty) and 13 for Everything (one more request, ~16 KB, completes the 365-day window)."
          },
          "calendarDays": {
            "title": "Daily calendar rows",
            "type": "boolean",
            "description": "Also deliver the calendar day by day: one row per listing and day (about 365 per listing) in the 'calendar' dataset, with availability, check-in/check-out allowed and minimum and maximum nights. Charged as calendar-days: $0.25 per 1,000 listing-months, so $3.00 per 1,000 listings for 12 months. Off (the default): each listing still carries its occupancy, ADR and revenue estimates from the calendar. Only with Revenue & occupancy, Everything and Find management leads.",
            "default": false
          },
          "maxReviewPages": {
            "title": "Max review pages per listing",
            "minimum": 0,
            "type": "integer",
            "description": "Reviews come in pages of 50, most recent first (Everything level). Empty or 0 = all reviews. Each review is charged, so a cap keeps the cost of listings with hundreds of reviews predictable."
          },
          "estimateCleaning": {
            "title": "Estimate the cleaning fee (+2 requests per listing)",
            "type": "boolean",
            "description": "Airbnb folds cleaning and service fees into the nightly rate. With this on, 2 extra price quotes per listing (different stay lengths) estimate the fixed per-stay part (estimates.cleaning_fee_estimated). Off by default: it adds 2 requests to the 3-4 of a listing (about +50 % run time) for a low-confidence estimate.",
            "default": false
          },
          "hostProfile": {
            "title": "Host profile",
            "enum": [
              "off",
              "count",
              "full"
            ],
            "type": "string",
            "description": "Count (default, free): one small request per unique host (~1.9 KB) for the host's total number of Airbnb listings, what tells an individual from a management company (it feeds the professional-host flag and the management-lead score). Full: the host's whole public profile (~7 KB per unique host): listings, years on Airbnb, sign-up month, verifications and the business verification badge; charged as host-profile, once per unique host ($1.00 per 1,000 hosts on the Free plan). Languages, 'lives in', work and the business label come free from the listing page's host card when it shows them (it shows 2 of the host's lines at a time; 'lives in' and work are empty with Omit personal data). Off: no profile requests. Needs the listing page (Details or higher).",
            "default": "count"
          },
          "omitPersonalData": {
            "title": "Omit personal data",
            "type": "boolean",
            "description": "Set host and co-host names, photos, bios, 'lives in' and work, and reviewer names, photos and profile links to null; replace the host's name with \"the host\" in Airbnb-generated texts (price-drop notice, listing highlights); the market report then shows no host names or listing titles. GDPR-friendly. What stays: numeric host and reviewer ids, the reviewer's location label, business data (ratings, Superhost, years hosting, license numbers) and free text as people wrote it (review text, host responses, listing descriptions), which can still contain names.",
            "default": false
          },
          "retryLocationAb": {
            "title": "Retry listings without neighborhood text",
            "type": "boolean",
            "description": "Airbnb hides the neighborhood name and area text for about half of the sessions (an A/B test). When on, such listings are fetched again with a new session, up to 'Listing page retries' times (about +0.5 requests per listing and retry).",
            "default": false
          },
          "pdpRetryAttempts": {
            "title": "Listing page retries",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Airbnb sometimes (about 1 in 9 requests) sends a listing page with only 5 of its photos. Such pages are fetched again with a new session up to this many times and the most complete answer is kept (also used by the neighborhood-text retry above). 0 = never retry.",
            "default": 1
          },
          "hostFeePct": {
            "title": "Host fee (for net revenue)",
            "pattern": "^(0(\\.\\d+)?)?$",
            "type": "string",
            "description": "Fraction Airbnb keeps from the host, used for estimates.revenue_net_of_platform_fee, e.g. 0.155. Empty = not computed."
          },
          "pushMode": {
            "title": "Delivery",
            "enum": [
              "auto",
              "incremental",
              "end"
            ],
            "type": "string",
            "description": "Automatic (default): Incremental, except Find management leads, which delivers at the end so that the dataset comes ranked best lead first with the scores filled in. Incremental: each listing (with its reviews and calendar) is saved and charged as soon as it is complete, so you see results from the first minutes and nothing is lost if the run stops. The few fields that compare a listing with the rest of the run (host's listings in this run, shared license numbers, price and rating vs. similar listings, suspected duplicates) are null in each listing, flagged with scrape.dataset_annotations_pending, and delivered at the end in the 'annotations' dataset (join by listing_id) and the MARKET_SUMMARY record. End: everything is saved at the end with those fields filled in, but nothing appears until the run finishes, an abort loses what was not saved in its last 30 seconds (a timeout is handled: the run stops itself about 90 seconds before it), and an unexpected crash loses the results.",
            "default": "auto"
          },
          "outputLayout": {
            "title": "Output layout",
            "enum": [
              "separate",
              "nested",
              "single_dataset"
            ],
            "type": "string",
            "description": "Separate: listings in the default dataset, reviews and calendar days in their own datasets (best for CSV/Excel; join by listing_id). Nested: reviews and days inside each listing (best for JSON/API; needs Output format = Full JSON). Single dataset: everything in the default dataset, told apart by record_type.",
            "default": "separate"
          },
          "proxyStrategy": {
            "title": "Proxy strategy",
            "enum": [
              "auto",
              "datacenter",
              "residential"
            ],
            "type": "string",
            "description": "Auto (recommended): starts with Apify datacenter proxies and switches to residential proxies only if Airbnb starts blocking (2 blocks in the last 50 requests: a request blocked on 2 datacenter IPs makes its third attempt through residential); after 300 clean requests on residential it tries datacenter once more. If residential proxies are not available to the run, it slows down instead. Datacenter / Residential: always that kind. Proxy traffic is not billed to you separately: the event prices include it. The log, the status message and the OUTPUT record show requests, blocks and estimated traffic per proxy level.",
            "default": "auto"
          },
          "proxyCountry": {
            "title": "Residential proxy country",
            "pattern": "^([A-Za-z]{2})?$",
            "type": "string",
            "description": "Optional 2-letter country code for residential proxies. Empty = US, like the datacenter proxies: Airbnb shows totals before taxes to visitors outside the EU, so every run's prices mean the same. An EU country (e.g. DE) makes Airbnb show totals with taxes (the taxes column fills in). Prices are always in the selected currency."
          },
          "proxyConfiguration": {
            "title": "Fixed proxy (overrides the strategy)",
            "type": "object",
            "description": "Optional. Set it only to force a specific Apify Proxy group: it is used as is for the whole run, with session rotation but without the automatic datacenter -> residential ladder. Your own proxy URLs and runs without a proxy are not supported: the Actor scrapes through Apify Proxy, one IP per parallel listing. Leave it unset to use 'Proxy strategy'."
          },
          "maxConcurrency": {
            "title": "Parallel listings",
            "minimum": 20,
            "maximum": 32,
            "type": "integer",
            "description": "Listings scraped at the same time, each through its own Apify Proxy IP with its own pause (a listing's price quote, policies and calendar are requested together with its page, as a browser loads it). 20 to 32; the default, 32, scrapes about 5 listings a second with the default 4 GB of memory. The minimum keeps a run's duration, which the event prices include, bounded. With your own proxy URLs or without a proxy (one IP), the pause is shared and more parallel listings are not faster.",
            "default": 32
          },
          "delaySeconds": {
            "title": "Pause between requests",
            "minimum": 1,
            "maximum": 2,
            "type": "integer",
            "description": "Minimum seconds between two requests from the same IP (plus up to 1 s of random jitter); a listing's quote, policies and calendar go out with its page. 1 (the default, the fastest) or 2. If Airbnb blocks, the Actor slows down and changes proxies by itself.",
            "default": 1
          },
          "maxRequests": {
            "title": "Max requests to Airbnb",
            "minimum": 0,
            "type": "integer",
            "description": "Hard cap on requests to airbnb.com for the whole run (retries included). 0 = no cap.",
            "default": 0
          },
          "saveRawResponses": {
            "title": "Save raw responses (debug)",
            "type": "boolean",
            "description": "Keep every raw Airbnb response in the key-value store (RAW_RESPONSES, tar.gz). Only useful for debugging.",
            "default": false
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}