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, or the listing has no active channel listing.
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.