Skip to content

Calendar

Endpoint Method Scope Description
/api/v1/listings/<id>/calendar/ GET reservations:read Get calendar data for a listing

Try it out

Explore parameters, schemas, and live requests in the Swagger UI.

Get Listing Calendar

Returns daily calendar data for a listing, including pricing, availability, and pricing factors — one entry per date in the requested range.

Calendar price fields are returned in the listing's own currency — the one the listing resource reports as currency. It is not the owner's billing currency, which is what market insights rates are priced in.

Request

GET /api/v1/listings/123/calendar/
    ?filter[start-date]=2026-03-10
    &filter[end-date]=2026-03-11
    &sort=date
Parameter Description
filter[start-date] First date (YYYY-MM-DD). Defaults to today in the listing's timezone.
filter[end-date] Last date (YYYY-MM-DD). Defaults to today + 365 days. Must not be before filter[start-date].
sort date (ascending, default) or -date. Any other field is a 400.
fields[calendar-entries] JSON:API sparse fieldset — return only the named attributes.
page[number], page[size] Standard pagination. Default page size 366, maximum 731. See below.

Pagination

This endpoint's page size is much larger than the API-wide default, so a normal date range arrives in a single response:

Parameter Default Maximum
page[size] 366 731

The default 365-day window therefore returns one page. Do not paginate it into 25-entry pages — that would turn one request into fifteen and, across a portfolio, run you into rate limits.

The filter names are filter[start-date] and filter[end-date]

This endpoint reads those two parameters by exact name. Any other filter[…] key — filter[start] and filter[end] included — is ignored without an error, and you get the default today → today + 365 window back with a 200. If the dates in the response are not the ones you asked for, check the parameter names.

Response

{
  "data": [
    {
      "type": "calendar-entries",
      "id": "2026-03-10",
      "attributes": {
        "date": "2026-03-10",
        "availability": "available",
        "price": 101,
        "price-posted": 100,
        "effective-min-price": 80,
        "effective-max-price": 250,
        "price-override-type": null,
        "factors": [
          {
            "key": "seasonality",
            "order": 1,
            "ratio": 0.12,
            "amount": 11
          },
          {
            "key": "event",
            "order": 2,
            "ratio": 0.05,
            "amount": 5,
            "reason": "City Marathon",
            "event-impact": "high"
          },
          {
            "key": "feature_occupancy_premium",
            "order": 3,
            "ratio": 0.03,
            "amount": 3,
            "metadata": {
              "listing-occupancy": 45.45,
              "market-occupancy": 27.32
            }
          }
        ]
      }
    }
  ],
  "meta": {
    "pagination": {"page": 1, "pages": 1, "count": 1}
  }
}

An entry's id is its date string, so type + id is unique per listing request.

Availability Values

Value Description
available The date is available to be booked
booked The date has a corresponding reservation
blocked The date is blocked off for a hold
unavailable The date cannot be booked for an unknown reason

Price Fields

All price fields are integers in whole currency units: a price of 189 on a USD listing is $189 per night. Values are never expressed in cents — do not divide by 100.

Field Description
price Beyond Pricing suggested price (shown in the BP dashboard)
price-posted Last price posted to the channel/PMS (null when never posted)
effective-min-price Effective minimum price floor; the modeled price will not go below this
effective-max-price Effective maximum price ceiling; the modeled price will not exceed this (null when unset)
price-override-type Which manual override, if any, produced price (null when the price is purely modeled)

Tip

Use price-posted when you need the price that will actually be quoted if a booking is made. Fall back to price if price-posted is null.

Manual Override State

price-override-type tells you whether someone has taken over pricing for a date:

Value Meaning
null No manual override. price is Beyond's modeled price and moves as the model updates.
fixed A fixed price is pinned to the date. price is that exact amount and Beyond will not reprice the date.
percentage A percentage adjustment is applied on top of the modeled price. price still moves as the model updates.

The override values — and the ability to set or clear them — live on the manual overrides customization.

Pricing Factors

Each calendar entry includes a factors array describing the individual components that shaped the modeled price (e.g. seasonality, day-of-week, events).

Field Description
key Factor identifier (e.g. seasonality, dow, event)
order Display/application order of the factor
ratio Factor's contribution as a ratio (e.g. -0.19 means -19%)
amount Factor's contribution to the modeled price, in the same whole currency units as price (e.g. -19 lowered the price by $19 on a USD listing)
reason Human-readable reason for the factor (e.g. event name); omitted for factors that carry none, and null for an event with no name
event-impact Event impact level (low, medium, high); only present for event factors
metadata Extra context specific to the factor's type; only present for the factors listed below

Note

amount values do not necessarily sum to (price − base price). Minimum/maximum price limits and final rounding are applied between factors and are not attributed to any single factor, and factors whose effect rounds to less than 1 report 0.

Factor Metadata

A few factor types carry extra context in a metadata object explaining what drove them. Each key belongs to one factor type and is absent for all the others, so read metadata against the factor's key rather than assuming a fixed shape.

Key Present on Description
listing-occupancy feature_occupancy_premium, feature_occupancy_discount The listing's occupancy over the factor's date range, as a percentage (e.g. 45.45 means 45.45%). null when Beyond has no reading for the listing
market-occupancy feature_occupancy_premium, feature_occupancy_discount The listing's market's occupancy over the same range, as a percentage. null when Beyond has no reading for the market
bedroom pacing_premium, pacing_discount Bedroom count the pacing factor was looked up under
bad-review-date reputation_discount Date of the review that triggered the discount (YYYY-MM-DD), once the triggering review is known

Together these let you explain a factor rather than just report it — for example, a feature_occupancy_premium with listing-occupancy: 45.45 and market-occupancy: 27.32 raised the price because the listing is filling faster than its market.

Use cases

  1. Price display. Show price-posted (falling back to price) beside your PMS rates to confirm what Beyond is publishing for each date.
  2. Price explanation. Render the factors array — with reason, event-impact, and metadata — to explain why a date is priced the way it is, instead of just reporting the number.
  3. Override audit. Scan a range for price-override-type != null to find dates where a person has taken over pricing, then read the values from the manual overrides customization.
  4. Floor/ceiling checks. Compare price with effective-min-price / effective-max-price to see which dates are pinned to a limit rather than floating with demand.

Errors

Status Cause
400 Listing not yet clustered (see below); invalid dates (end before start, malformed YYYY-MM-DD); invalid sort field; insufficient cluster data.
401 Missing or invalid bearer token.
403 Token does not have the reservations:read scope.
404 No listing with that id is visible to your application.
429 Rate limit exceeded. See Rate Limiting.

Not Yet Clustered (400)

A listing that has no pricing cluster assigned cannot serve its calendar: the endpoint returns a 400 with a "not yet clustered" message. Most listings are clustered as part of the initial import, so this is uncommon — it happens when a listing was created without a cluster, or lost its cluster later. The listing resource surfaces this state through in-active-market, which is false while the listing has no cluster (and true only when the calendar is available). The listing.in_active_market_changed webhook tells you when a priced listing's in-active-market changes in either direction — no polling needed.