Apify Toolkits

Attraction availability

Day-level bookability over a window, optionally with timeslots. Each timeslot date is a separate upstream request, capped at 14.

Describes build 1.0.173 of rl1987/booking-api-scraper, deployed 2026-10-29. The column set last changed 2026-10-29. Earlier builds can return a different one.

Modes: attractionAvailability
Dataset view: attractionAvailability — ?view=attractionAvailability on the items API, or the matching tab in the Console.

Day-level bookability over a window, optionally with timeslots. Each timeslot date is a separate upstream request, capped at 14.

20 columns, in the order the view shows them.

#ColumnLabelTypeDescriptionExample
1scrapedAtScraped atstring, nullableWhen the response that produced this row came back - the PRICED response where the row has a price, not when the row was pushed, which is batched and later by seconds to minutes. ISO-8601 UTC, to milliseconds. Note Booking’s own date strings in the same row are NOT ISO (freeCancellationUntil is “2026-10-28 23:59:59 +0000”), so do not point one parser at both. Prices are fetched live - nothing in this Actor is cached or reused - so this is the age of the price, and a dataset read a week later does not refresh it.2026-10-27T12:53:42.118Z
2scrapedAtUnixScraped at (epoch)integer, nullableThe same instant as scrapedAt, in epoch SECONDS, for consumers that diff timestamps arithmetically. Two keys rather than one selectable format, so a column’s type never moves with a run setting and two datasets always join.1793105622
3attractionIdAttraction IDstring, nullableBooking’s attraction product id.PRDF8MpWklG6
4provenanceProvenanceobject, nullableWhat produced this row’s price: the proxy exit it was fetched through, the generation of that exit, the currency you asked for and the endpoint that priced it. The point of sale follows the proxy exit country, not any input - bookerCountry was removed in this build because nothing read it.
5statusStatusstring, nullableRates mode: “available”, “not_offered” or “lookup_failed” - the last means we could not ask, the middle means Booking answered and the rate is not on sale. attractionAvailability mode: null means dates were bookable inside your window; no_availability_in_window is the real negative - days were checked and none were bookable; window_outside_calendar means the attraction is real but your window falls outside the span Booking publishes, so nothing was checked at all and calendarFrom/calendarTo give that span; not_found means the id resolved to nothing. That last one is INFERRED rather than reported: Booking answers an unknown id with a successful but empty calendar rather than an error, so an empty calendar is the discriminator - and it also covers an attraction withdrawn from sale. Telling the three negatives apart matters, because only the middle one means the attraction has no dates for you.available, not_offered
6errorErrorstring, nullableAttractions modes: the upstream message when an id could not be looked up.Not Found (attractions backend 404)
7windowStartWindow startstring, nullableStart of the window you asked about.
8windowEndWindow endstring, nullableEnd of the window you asked about.
9bookableInWindowBookable in windowboolean, nullableWhether any day in the window is bookable.
10availableDayCountAvailable daysinteger | number, nullableBookable days inside the window.
11unavailableDayCountUnavailable daysinteger | number, nullableChecked days that are not bookable.
12daysCheckedDays checkedinteger | number, nullableDays of the calendar inside your window.
13firstAvailableDateFirst availablestring, nullableEarliest bookable day in the window.
14lastAvailableDateLast availablestring, nullableLatest bookable day in the window.
15availableDatesAvailable datesarray, nullableDates bookable in the window.
16calendarFromCalendar fromstring, nullableFirst day Booking publishes for this product.
17calendarToCalendar tostring, nullableLast day Booking publishes for this product.
18timeslotDatesFetchedTimeslot dates fetchedinteger | number, nullableHow many dates timeslots were fetched for, capped by attractionsTimeslotDays (default 3, maximum 14). Each one is a separate upstream request.
19timeslotsTimeslotsarray, nullableEvery timeslot on the fetched dates, with its offers, ticket types, prices and remaining inventory.
20recordTypeRecord typestring, nullableWhich kind of row this is. Absent on property rows (search, rooms, details, surroundings, reviews, reviewScores); “rate” in mode rates; “attraction”, “attractionDetail” or “attractionAvailability” in the attractions modes. One dataset can hold several kinds, so filter on this before reading kind-specific columns.rate, attraction

Inside the nested columns

Some columns above carry an object, or a list of objects, with documented members of their own. Each table below lists the members documented at ONE level; a member that is itself an object names the table it continues in, and [] in a path means a list.

row
└─ provenance

provenance — Provenance

Parent chain: row → provenance

What produced this row’s price: the proxy exit it was fetched through, the generation of that exit, the currency you asked for and the endpoint that priced it. The point of sale follows the proxy exit country, not any input - bookerCountry was removed in this build because nothing read it.

#FieldLabelTypeDescriptionExample
1exitCountryExit countrystring, nullableISO country of the proxy exit this row was fetched through, sampled once per proxy generation from Apify’s own request echo. This is the market that priced the row: on the hotel_ids path taxes come back inside the display price from an EU exit and excluded through a US one. Null when the run’s pool rotates per request (a residential proxy with no session), when the probe failed, or past the per-run probe budget - null means not established, not “no market”. Pin country-XX or a session in the proxy configuration to make it exact for every row.US, GB
2proxyGenerationProxy generationinteger, nullableWhich exit fetched this row, counted from 0. The retry ladder draws a fresh exit when one fails - six generations in 30 seconds on one measured run - so two rows of one dataset can honestly carry different tax treatment. RUN_SUMMARY.request.exitCountries lists every generation and its country.0
3currencyRequestedCurrency requestedstring, nullableThe currency you asked for, beside the honoured currency. Not recoverable from the row otherwise: HOTEL resolves to the property’s own code, which the row then states as its own currency - so a row quoting MYR could have been asked for as HOTEL or as MYR.EUR, HOTEL
4surfaceSurfacestring, nullableThe endpoint that produced this row: search (the destination search), roomList (the per-property rate list) or hotelPage (the by-id path). The surfaces disagree in documented ways - roomList carries the structured meal price and hotelPage does not - so a buyer comparing two rows needs to know which answered.roomList, hotelPage

A real row

Captured from a live run. Lists are cut to two entries and deep nesting is elided — the shape is real, the bulk is not.

{
  "status": null,
  "recordType": "attractionAvailability",
  "attractionId": "PRlcMuKM2k7R",
  "windowStart": null,
  "windowEnd": null,
  "availableDates": [
    "2026-10-24",
    "2026-10-25",
    "... 177 more"
  ],
  "availableDayCount": 179,
  "unavailableDayCount": 2,
  "daysChecked": 181,
  "bookableInWindow": true,
  "firstAvailableDate": "2026-10-24",
  "lastAvailableDate": "2027-04-20",
  "calendarFrom": "2026-10-23",
  "calendarTo": "2027-04-21",
  "timeslots": [
    {
      "date": "2026-10-24",
      "timeSlotId": "ATS-PRlcMuKM2k7R-202610240900-nullnull",
      "start": "2026-10-24T09:00:00+03:00",
      "fullDay": false,
      "offerId": "OF5sZQfwtNtx",
      "offerLabel": "Vilnius: The Women of Vilnius 2-Hour Tour",
      "ticketLabel": "Adult",
      "ticketType": "adult",
      "ticketsAvailable": 10000,
      "minPerReservation": 4,
      "maxPerReservation": 4,
      "price": 149,
      "currency": "USD"
    },
    {
      "date": "2026-10-24",
      "timeSlotId": "ATS-PRlcMuKM2k7R-202610240900-nullnull",
      "start": "2026-10-24T09:00:00+03:00",
      "fullDay": false,
      "offerId": "OF5sZQfwtNtx",
      "offerLabel": "Vilnius: The Women of Vilnius 2-Hour Tour",
      "ticketLabel": "Adult",
      "ticketType": "adult",
      "ticketsAvailable": 10000,
      "minPerReservation": 3,
      "maxPerReservation": 3,
      "price": 199,
      "currency": "USD"
    },
    "... 328 more"
  ],
  "timeslotDatesFetched": 3
}