Download OpenAPI specification:
The Wheelhouse Revenue Management API provides direct access to price recommendations, listing preferences, custom rates, reservations, and portfolio management for Revenue Management integrations.
This API is currently in beta. The interface and response formats may change in future versions.
When using this API through the Wheelhouse MCP server, authenticate with OAuth (WorkOS AuthKit). Sign in with your Wheelhouse account through your MCP client's OAuth flow — the same credentials you use in the Wheelhouse app.
Do not send an RM API key yourself. The MCP server validates your OAuth token, resolves your user-specific RM API key, and attaches it as X-Integration-Api-Key on every upstream request. Your OAuth token is never forwarded to the RM API.
For HTTP integrations that call the RM API directly, send an RM API key in the X-Integration-Api-Key header. You can generate this in your Wheelhouse account under "Api Key".
The RM API key is a single key that authenticates both the integration and user context — no separate user key is required.
Keys configured as read-only may use the HTTP methods GET, HEAD, OPTIONS, and POST only. PUT and DELETE requests return 403 Forbidden with a message that the API key is read-only (other disallowed methods do as well). POST endpoints that create or modify data (such as creating a note) also return 403 Forbidden for read-only keys; only non-mutating POST endpoints (such as previews) are allowed.
List endpoints that return large result sets support pagination via the page, per_page, and offset query parameters. per_page controls how many items are returned per page (up to 100). Use page (1-based) or offset (0-based item skip count) to advance through the result set — do not use both in the same request. Iterate by incrementing page until a response returns fewer items than per_page.
RM API keys are rate-limited to 60 requests per minute by default. Exceeding this limit returns 429 Too Many Requests. The limit resets on a rolling one-minute window.
Every response tells you where you stand, so you never have to guess or spend a request finding out:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Requests allowed per window for the key you used. |
X-RateLimit-Remaining |
Requests still available in the current window. Never negative. |
X-RateLimit-Reset |
Unix timestamp (seconds) when the window frees up. |
The request carrying the headers is itself counted, so an idle key's first response reports one fewer than the limit.
A 429 carries the same three headers plus Retry-After, the number of seconds to wait. Prefer Retry-After over your own backoff schedule when it is present — it is the actual reset, not an estimate.
If you receive a 429 and no Retry-After, wait before retrying. The recommended strategy is exponential backoff: after the first failure wait 1 second, then double the delay on each subsequent retry (2 s, 4 s, 8 s, …), up to a reasonable maximum (e.g. 60 seconds). Adding a small random jitter (±10–20% of the wait time) prevents multiple concurrent clients from retrying in lockstep.
If your integration regularly reaches the limit, consider batching requests (e.g. using GET /preferences or PUT /preferences for multiple listings at once) or contact Wheelhouse to discuss a higher limit.
Most endpoints require a listing_id and channel path or query parameter to identify the listing a request is being made for. There are two ways to fill them in, and both values come from the GET /listings endpoint (see Listings).
By channel listing ID (default). A channel's listing IDs are only unique within that channel, so channel is what disambiguates them:
listing_id — the id field from the listing object.channel — the channel field from the same listing object.By Wheelhouse listing ID. Pass the literal value wheelhouse as channel, and listing_id is read as a Wheelhouse listing ID:
listing_id — the wheelhouse_id field from the listing object.channel — the literal string wheelhouse.Wheelhouse listing IDs are unique across all channels, so no channel has to be named alongside them. This is the more convenient form when you already hold Wheelhouse IDs — for example from GET /listings/kpis, which returns them as listing_id, or from a Wheelhouse listing URL. Note that the two ID spaces are distinct: passing a Wheelhouse ID without channel=wheelhouse, or a channel listing ID with it, returns 404 Not Found.
Either form works anywhere a listing is identified, including the batched listing_ids parameters on GET /preferences, PUT /sets/{set_id}/associated_listings, and DELETE /sets/{set_id}/associated_listings, and the copy_preferences_from object on PUT /preferences/{listing_id}/copy (whose nested channel is resolved independently of the top-level one, so the source and target listing may each be identified their own way).
Which form you use does not change what you can reach: a Wheelhouse listing ID grants no access to a listing that a channel listing ID would not. It does change how an unreachable listing is reported. Because Wheelhouse IDs are sequential and span every account, a listing you cannot access returns 404 Not Found under channel=wheelhouse — the same response as an ID that matches nothing — so that the ID space cannot be walked to discover other accounts' listings. Under a channel listing ID, a listing you cannot access still returns 403 Forbidden. Listings shared with you to manage are reachable under both forms.
A typical flow is to call GET /listings once to build a local map of your listings, then use the id and channel values from that map — or each listing's wheelhouse_id with channel=wheelhouse — for all subsequent listing-specific calls.
Some listings represent a single bookable property that has multiple independently bookable units underneath it — for example, a building with several apartments, or a property with a main house and a guest cottage managed as one listing. These are called multi-unit listings.
You can identify a multi-unit listing by the number_of_active_units field on the listing object (returned by GET /listings and GET /listings/{listing_id}). A non-null value indicates a multi-unit listing; null indicates a standard single-unit listing.
For endpoints that return per-date data (such as GET /listings/{listing_id}/price_calendar and GET /listings/{listing_id}/last_posted_prices), multi-unit listings return one row per unit per date. Each row includes a unit_number field (a positive integer starting at 1) that identifies which unit the row belongs to. Single-unit listings always return unit_number: 0.
When processing calendar data for a multi-unit listing, group rows by unit_number to get the per-unit availability and pricing. Preferences and settings (fetched via GET /preferences/{listing_id}) apply at the listing level and are shared across all units.
Returns every listing the authenticated user can access: listings they own (connected via their channel accounts) plus listings they have been granted access to manage in Wheelhouse (shared / delegated access on another user's listings). Set include_managed_listings to false to restrict the response to owned listings only. Each listing carries an access_level and an owner_user, so managed listings can be told apart from owned ones and attributed to the account they belong to.
| exclude_inactive | boolean Default: true Exclude inactive listings from the response. |
| include_managed_listings | boolean Default: true When true (default), includes listings the user manages for another Wheelhouse account (valid shared-access grants), in addition to listings they own. Set to false to return only owned listings. |
| per_page | integer [ 1 .. 100 ] Default: 50 Number of listings per page. |
| page | integer Page number to retrieve. |
| offset | integer Number of items to skip before starting to collect the result set. |
[- {
- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}
]Returns a single rolling-window KPI for every listing the authenticated user can access, ranked by value. Use it to answer portfolio-wide questions — the best or worst performers on a metric — in one call instead of one call per listing.
Pick the metric with metric and the window with window, where 0_30 is the
next 30 days and 30_0 the trailing 30. Values come from the same store as
GET /listings/{listing_id}/kpis, so the two
always agree; that endpoint remains the way to read every metric and window for
one listing.
Metrics (window 0_N and N_0): adr, adr_fees, asking_rate,
asking_rate_fees, asking_rate_highest, asking_rate_lowest, bookings,
last_booked_days, lead_time, length_of_stay, min_price_occurrence,
nights_available, nights_blocked, nights_bookable, nights_booked,
nights_calendar, nights_percent_open, occupancy, occupancy_adjusted,
revenue, revenue_available, revenue_blocked, revenue_fees,
revenue_fees_taxes, revpar, revpar_adjusted_occupancy,
revpar_adjusted_occupancy_fees, revpar_fees.
Forward-only metrics (window 0_N only): occupancy_neighborhood,
occupancy_neighborhood_pp, occupancy_neighborhood_ratio,
occupancy_neighborhood_adjusted, occupancy_neighborhood_adjusted_pp,
occupancy_neighborhood_adjusted_ratio, revenue_score.
Backward-only metrics (window N_0 only): pickup, pickup_bookings.
Asking for a window a metric is not computed for returns a 400.
Monetary metrics — the adr, asking_rate, revenue and revpar families —
are stored in the currency of the listing's market, falling back to the
listing's own currency when it has no market, and each row reports which in its
currency. For a portfolio spanning currencies, pass currency to convert
every value before ranking, so that the ordering is meaningful. Without it,
rows are ranked on unconverted numbers. currency is ignored for metrics that
are not amounts of money.
A listing with no value for the requested window sorts last whichever direction
you rank in, with value set to null, so a ranking never opens with blanks.
Listings for which no stats have been generated at all are absent. Values are
recomputed by the nightly stats pipeline and when a listing's calendar is
refreshed; updated_at on each row tells you how current it is.
Comp-set metrics (comp_set_occupancy and friends) are not available here yet.
| metric required | string Example: metric=occupancy_adjusted The KPI to return. See the metric lists above. |
| window required | string Enum: "0_7" "0_14" "0_21" "0_30" "0_60" "0_90" "0_180" "0_365" "7_0" "14_0" "21_0" "30_0" "60_0" "90_0" "180_0" "365_0" Example: window=0_30 Window to return. |
| sort | string Default: "desc" Enum: "desc" "asc" Rank highest value first ( |
| currency | string Example: currency=USD ISO-4217 code to convert monetary values to before ranking. Recommended for portfolios spanning more than one currency. Ignored for metrics that are not amounts of money. |
| exclude_inactive | boolean Default: true Exclude inactive listings from the ranking. |
| include_managed_listings | boolean Default: true When true (default), includes listings the user manages for another Wheelhouse account, in addition to listings they own. Set to false to rank only owned listings. |
| page | integer Default: 1 Page of the ranking to return. |
| per_page | integer <= 100 Default: 50 Rows per page (max 100). |
[- {
- "listing_id": 84521,
- "partner_listing_id": "12345",
- "value": 0.82,
- "currency": "USD",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "name": "Free",
- "horizon": 0
}| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "settings": "2019-08-24T14:15:22Z",
- "rates": "2019-08-24T14:15:22Z"
}Enqueues a price-posting job that pushes the latest Wheelhouse price recommendations to the connected channel and refreshes reservation data. Equivalent to clicking the Sync button in the Wheelhouse UI.
Plan requirement: Manual syncs are only available on paid (Pro) plans. Listings on
free or onboarding plans will receive 429 Too Many Requests.
Rate limit: The number of syncs allowed per day is determined by the listing's pricing
plan. Returns 429 Too Many Requests when the daily limit is exceeded.
Debounce: To prevent duplicate jobs from stacking up, if another sync for the same
listing was requested within the last 60 seconds, the endpoint returns 423 Locked.
Wait at least 60 seconds before retrying.
The request returns 202 Accepted immediately — the sync runs asynchronously in the
background. Use GET /listings/{listing_id}/pricing_tier or poll the Wheelhouse
dashboard to confirm when the sync has completed.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
Returns rolling-window performance metrics covering the full
Wheelhouse metrics lexicon.
Each metric is an object keyed by period strings such as "0_7" (next 7 days),
"0_30" (next 30 days), "30_0" (past 30 days), etc.
Bidirectional metrics (periods 7/14/21/30/60/90/180/365, both past and future):
adr, adr_fees, asking_rate, asking_rate_fees, asking_rate_highest,
asking_rate_lowest, bookings, last_booked_days, lead_time, length_of_stay,
min_price_occurrence, nights_available, nights_blocked, nights_bookable,
nights_booked, nights_calendar, nights_percent_open, occupancy,
occupancy_adjusted, revenue, revenue_available, revenue_blocked,
revenue_fees, revenue_fees_taxes, revpar, revpar_adjusted_occupancy,
revpar_adjusted_occupancy_fees, revpar_fees.
Forward-only metrics (periods 7/14/21/30/60/90/180/365, future only):
occupancy_neighborhood, occupancy_neighborhood_pp, occupancy_neighborhood_ratio,
occupancy_neighborhood_adjusted, occupancy_neighborhood_adjusted_pp,
occupancy_neighborhood_adjusted_ratio, revenue_score.
Backward-only metrics (periods 7/14/21/30/60/90/180/365, past only):
pickup, pickup_bookings.
Comp-set metrics (periods 7/30/60, forward only):
comp_set_occupancy, comp_set_occupancy_adjusted, comp_set_revenue.
Scalars: comp_set_count.
A metric field is null when it has not been generated yet for the listing;
individual period keys are null where the metric does not apply or the window
has no data. All monetary values are in the listing's currency.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "currency": "USD",
- "model_date": "2019-08-24",
- "adr": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "adr_fees": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "asking_rate": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "asking_rate_fees": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "asking_rate_highest": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "asking_rate_lowest": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "bookings": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "comp_set_count": 0,
- "comp_set_occupancy": {
- "0_7": 0,
- "0_30": 0,
- "0_60": 0
}, - "comp_set_occupancy_adjusted": {
- "0_7": 0,
- "0_30": 0,
- "0_60": 0
}, - "comp_set_revenue": {
- "0_7": 0,
- "0_30": 0,
- "0_60": 0
}, - "last_booked_days": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "lead_time": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "length_of_stay": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "min_price_occurrence": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_available": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_blocked": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_bookable": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_booked": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_calendar": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "nights_percent_open": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "occupancy": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "occupancy_adjusted": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "occupancy_neighborhood": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "occupancy_neighborhood_adjusted": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "occupancy_neighborhood_adjusted_pp": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "occupancy_neighborhood_adjusted_ratio": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "occupancy_neighborhood_pp": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "occupancy_neighborhood_ratio": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "pickup": {
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "pickup_bookings": {
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue_available": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue_blocked": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue_fees": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue_fees_taxes": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revenue_score": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0
}, - "revpar": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revpar_adjusted_occupancy": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revpar_adjusted_occupancy_fees": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}, - "revpar_fees": {
- "0_7": 0,
- "0_14": 0,
- "0_21": 0,
- "0_30": 0,
- "0_60": 0,
- "0_90": 0,
- "0_180": 0,
- "0_365": 0,
- "7_0": 0,
- "14_0": 0,
- "21_0": 0,
- "30_0": 0,
- "60_0": 0,
- "90_0": 0,
- "180_0": 0,
- "365_0": 0
}
}Returns per-month performance stats, ordered oldest-to-newest. Includes comp-set metrics.
Covers both past and future months — up to 15 months back and up to 12 months forward,
subject to the months Wheelhouse holds data for. Months from the current one onward are
forward-looking: they reflect the bookings on the books so far plus asking rates for nights
that are still open, so they are not final and will change as bookings come in. Compare a
month's month value against today's date to tell which side of the line it falls on.
All monetary values are in the listing's currency.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "currency": "USD",
- "data": [
- {
- "month": "2019-08-24",
- "adr": 0,
- "adr_fees": 0,
- "asking_rate": 0,
- "lead_time": 0,
- "los": 0,
- "nights_available": 0,
- "nights_blocked": 0,
- "nights_bookable": 0,
- "nights_booked": 0,
- "nights_percent_open": 0,
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "revenue": 0,
- "revenue_available": 0,
- "revenue_blocked": 0,
- "revenue_fees": 0,
- "revenue_fees_taxes": 0,
- "revpar": 0,
- "revpar_fees": 0,
- "revpar_adjusted_occupancy_fees": 0,
- "revpar_adjusted_occupancy": 0,
- "comp_set_adr": 0,
- "comp_set_lead_time": 0,
- "comp_set_occupancy": 0,
- "comp_set_occupancy_adjusted": 0,
- "comp_set_revpar": 0,
- "comp_set_revenue": 0,
- "comp_set_revpar_adjusted_occupancy": 0,
- "comp_set_los": 0
}
]
}Returns per-quarter performance stats, ordered oldest-to-newest.
Covers both past and future quarters — from the quarter containing the date 15 months
ago through the quarter containing the date 12 months from now, subject to the quarters
Wheelhouse holds data for. The current quarter and any that follow are forward-looking: they
reflect the bookings on the books so far plus asking rates for nights that are still open,
so they are not final and will change as bookings come in. Compare a quarter's quarter
value against today's date to tell which side of the line it falls on.
All monetary values are in the listing's currency.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "currency": "USD",
- "data": [
- {
- "quarter": "2019-08-24",
- "adr": 0,
- "adr_fees": 0,
- "asking_rate": 0,
- "lead_time": 0,
- "los": 0,
- "nights_available": 0,
- "nights_blocked": 0,
- "nights_bookable": 0,
- "nights_booked": 0,
- "nights_percent_open": 0,
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "revenue": 0,
- "revenue_available": 0,
- "revenue_blocked": 0,
- "revenue_fees": 0,
- "revenue_fees_taxes": 0,
- "revpar": 0,
- "revpar_fees": 0,
- "revpar_adjusted_occupancy_fees": 0,
- "revpar_adjusted_occupancy": 0
}
]
}Returns per-year performance stats, ordered oldest-to-newest.
Covers both past and future years — from 5 calendar years ago through the year containing
the date 12 months from now, subject to the years Wheelhouse holds data for. The current year
and the next one are forward-looking: they reflect the bookings on the books so far plus
asking rates for nights that are still open, so they are not final and will change as
bookings come in. Compare a year's year value against today's date to tell which side of
the line it falls on.
All monetary values are in the listing's currency.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "currency": "USD",
- "data": [
- {
- "year": "2019-08-24",
- "adr": 0,
- "adr_fees": 0,
- "asking_rate": 0,
- "lead_time": 0,
- "los": 0,
- "nights_available": 0,
- "nights_blocked": 0,
- "nights_bookable": 0,
- "nights_booked": 0,
- "nights_percent_open": 0,
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "revenue": 0,
- "revenue_available": 0,
- "revenue_blocked": 0,
- "revenue_fees": 0,
- "revenue_fees_taxes": 0,
- "revpar": 0,
- "revpar_fees": 0,
- "revpar_adjusted_occupancy_fees": 0,
- "revpar_adjusted_occupancy": 0
}
]
}Retrieve Wheelhouse price recommendations, base price suggestions, check-in/check-out calendars, min/max price calendars, and monthly seasonality factors.
Returns most up-to-date price recommendations for the listing.
The horizon of the price recommendations depends on the pricing tier this listing is in and can be
queried using the pricing tier endpoint. Free listings get a
preview horizon of 30 days, while Pro listings get 18 months.
The data array starts from today's date and is returned in chronological order.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| currency | string ISO-4217 3-letter currency code (e.g. 'USD', 'GBP') to convert prices to. Uses listing's currency by default. |
| attribution | boolean Default: false When true, includes detailed per-factor price attribution fields ( |
| price_model | string Enum: "current" "opt_in" The price model version to use. If omitted, uses the price model currently active for the listing. |
{- "data": [
- {
- "stay_date": "2019-08-24",
- "price": 0,
- "currency": "string",
- "min_stay": 0,
- "custom_type": "string",
- "attr_seasonality": 0,
- "attr_local_demand": 0,
- "attr_availability": 0,
- "attr_time": 0,
- "attr_custom_weekend": 0,
- "attr_scarcity": 0,
- "attr_occupancy_pacing": 0,
- "attr_historical_anchoring": 0,
- "attr_restriction": 0,
- "attr_user_adjustment": 0
}
], - "base_price": 0,
- "base_price_recommended": 0,
- "base_price_conservative": 0,
- "base_price_aggressive": 0,
- "global_min_stay": 0,
- "automatic_rate_posting_enabled": true
}Returns price recommendations as if the provided preferences were applied to the listing, without actually saving any changes.
The response format is identical to GET /listings/{listing_id}/price_recommendations, except that global_min_stay and automatic_rate_posting_enabled are not included.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| automatic_rate_posting_enabled | boolean Whether Wheelhouse automatically posts its price recommendations to the channel calendar. When |
| base_price | integer or null >= 1 The manually set base price. If set, overrides Wheelhouse's data-driven recommendation. Must be a whole number of at least 1. |
| base_price_adjustment | number or null A percentage adjustment to the Wheelhouse recommended base price. Only used if |
| monthly_discount | integer or null Default: 0 Monthly discount percentage as an integer in the range 0–100 (e.g. |
| weekly_discount | integer or null Default: 0 Weekly discount percentage as an integer in the range 0–100 (e.g. |
| nickname | string or null Listing nickname. Overrides the listing's default nickname. |
object or null UI: 'Last minute' — Last-minute discount configuration. | |
object or null UI: 'Far future' — Far-future premium configuration. | |
object or null UI: 'Seasonality' — Seasonality adjustment configuration. | |
object or null Day-of-week pricing factor configuration. | |
object or null Gap night pricing strategy (UI: 'Gaps & Adjacencies' in the Pricing Engine panel). Controls the price multiplier for
gap nights between bookings. When | |
Array of any (integer_calendar_rule) Default: [] UI: 'Minimum stays' — minimum stay rules. The | |
| min_stays_enabled | boolean Whether minimum stay rules are enabled. |
Array of any Default: [] UI: 'Minimum prices' — Minimum price rules. Valid rule types: | |
Array of any Default: [] UI: 'Maximum prices' — Maximum price rules. Valid rule types: | |
object or null Check-in/check-out rule configuration identifier. | |
object Default: {"active":false,"weekly_rules":[],"monthly_rules":[],"rules":{}} Rule-based long-term discount configuration. | |
object or null Default: {} Occupancy pacing configuration. When | |
Array of any Default: [] Demand sensitivity rules. Valid rule types: | |
Array of any Default: [] Historical anchoring rules. Valid rule types: | |
Array of objects (custom_date_range) Default: [] Represents an Event or Season entry used by the Wheelhouse Events & Seasons feature.
Calendar rules reference these entries by Each listing stores its own copy of every Event or Season it belongs to. Entries for the
same event or season share the same To safely modify an event or season's definition (dates or name) on one listing without
affecting others, omit the A new | |
| min_min_price | integer Default: 0 UI: 'Absolute minimum price' — Hard lower bound that overrides all pricing rules. No recommended price will fall below this value regardless of any rule configuration. Distinct from a |
| min_min_stay | integer Default: 0 UI: 'Absolute minimum stay' — Hard lower bound that overrides all minimum stay rules. No minimum stay will be set below this value regardless of any rule configuration. Distinct from both a |
| apply_gap_night_rules_to_overrides | boolean UI: 'Apply Gap Night Rules to Overrides' — When |
| price_model | string Enum: "current" "opt_in" The price model version to use. If omitted, uses the price model currently active for the listing. |
{- "automatic_rate_posting_enabled": true,
- "base_price": 1,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true,
- "price_model": "current"
}{- "data": [
- {
- "stay_date": "2019-08-24",
- "price": 0,
- "currency": "string",
- "custom_type": "string"
}
], - "base_price": 0,
- "base_price_recommended": 0,
- "base_price_conservative": 0,
- "base_price_aggressive": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}, - "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}Returns recommended, conservative, and aggressive base prices, the listing's active base price, anchoring
fields (anchor_price, anchor_credibility), and a consolidated base_price_attribution object aligned with
the Wheelhouse app Recommended Breakdown.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| currency | string ISO-4217 3-letter currency code (e.g. 'USD', 'GBP') to convert prices to. Uses listing's currency by default. |
{- "base_price_recommended": 0,
- "base_price_conservative": 0,
- "base_price_aggressive": 0,
- "base_price_selected": 0,
- "anchor_credibility": 100,
- "anchor_price": 0,
- "base_price_attribution": {
- "market_baseline": 0,
- "bedrooms_bathrooms": 0,
- "room_type": 0,
- "guests": 0,
- "location": 0,
- "amenities_fees": 0,
- "occupancy": 0,
- "observed_bookings": 0
}, - "currency": "string"
}Returns a daily calendar of check-in and check-out rules. Returns 204 if check-in/check-out rules are not configured for the listing.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "data": [
- {
- "stay_date": "2019-08-24",
- "check_in": true,
- "check_out": true
}
]
}| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "data": [
- {
- "stay_date": "2019-08-24",
- "min_price": 0,
- "max_price": 0
}
]
}Returns conservative (CON), recommended (REC), and aggressive (AGG) seasonality multipliers grouped by month number (1–12).
The factors represent the average seasonality multiplier for each month based on market data and can be used to understand seasonal pricing patterns.
A factor of 1.0 means no seasonal adjustment, values above 1.0 indicate higher demand periods, and values below 1.0 indicate lower demand periods.
The three levels differ in how much they amplify the seasonality signal:
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "CON": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0,
- "6": 0,
- "7": 0,
- "8": 0,
- "9": 0,
- "10": 0,
- "11": 0,
- "12": 0
}, - "REC": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0,
- "6": 0,
- "7": 0,
- "8": 0,
- "9": 0,
- "10": 0,
- "11": 0,
- "12": 0
}, - "AGG": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0,
- "6": 0,
- "7": 0,
- "8": 0,
- "9": 0,
- "10": 0,
- "11": 0,
- "12": 0
}
}Returns a daily log of Wheelhouse base price recommendations and settings for the listing. Each record reflects the model's recommendation, any adjustments applied, and the effective base price used on that day.
Defaults to the last 30 days when start_date and end_date are omitted.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> First model date to include (YYYY-MM-DD). Defaults to 30 days before |
| end_date | string <date> Last model date to include (YYYY-MM-DD). Defaults to today. |
[- {
- "model_date": "2019-08-24",
- "raw_recommendation": 0,
- "recommendation": 0,
- "adjustment": 0.1,
- "fixed": 0,
- "anchor_price": 0,
- "anchor_weight": 0.1,
- "effective_base_price": 0.1
}
]Read and update detailed pricing preferences for listings, including base price, seasonality, discounts, min stay rules, and more.
Note: These preferences are called "Settings" in the Wheelhouse app.
Not every channel can act on every setting. Some have no concept of check-in/check-out day rules, some cannot take minimum stays, and support for long-term discounts ranges from none at all, through fixed weekly and monthly tiers, to arbitrary ones. Which settings a listing accepts therefore depends on the channel it is connected to.
A setting the channel cannot act on is not applied — it is discarded rather than stored, so it never appears to have taken effect. The rest of the request still applies, and the response is still a success.
Each listing reports what it accepts as supported_settings, on both the listing object and the preferences object. Read it before sending a setting rather than after: a setting reported false will be discarded. It reflects any per-account early access, so two listings on the same channel can differ.
Every write also returns warnings, naming each setting that was not applied, why, and which attributes it covered. The array is present and empty when everything applied, so it can be read unconditionally. reason is not_supported_by_channel when the channel has no such feature, or partially_supported_by_channel when it accepts a narrower form than what was sent and only the excess was dropped.
The Wheelhouse Settings panel organizes preferences into labeled groups. The table below maps each group to its corresponding API fields.
| UI Group | UI Setting Name | API Field(s) |
|---|---|---|
| Pricing Engine | Base price | base_price, base_price_adjustment |
| Pricing Engine | Seasonality | seasonality_adjustment |
| Pricing Engine | Day of week | day_of_week |
| Pricing Engine | Last minute | last_minute_discount |
| Pricing Engine | Far future | far_future_premium |
| Pricing Engine | Gaps & Adjacencies | gap_night |
| Model Weights | Demand sensitivity | demand_sensitivity_rules |
| Model Weights | Historical anchoring | historical_anchoring_rules |
| Limits | Maximum prices | maximum_price_rules_v3 |
| Limits | Minimum prices | minimum_price_rules_v3, min_min_price |
| Operations | Minimum stays | minimum_stay_rules_v3, min_min_stay |
| Operations | Length of stay pricing | long_term_discounts, weekly_discount, monthly_discount |
| Calendar Pacing | Occupancy pacing | occupancy_pacing |
| Configuration | Events & Seasons | custom_date_ranges |
| channel required | string Channel name the listing is on (the |
| listing_ids | Array of strings Array of channel listing IDs to retrieve preferences for, or Wheelhouse listing IDs when |
[- {
- "listing_id": 0,
- "partner_listing_id": "string",
- "currency": "string",
- "automatic_rate_posting_enabled": true,
- "base_price": 0,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true,
- "update_from": "string",
- "update_from_id": 0,
- "created_at": "string",
- "updated_at": "string",
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}, - "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}
]Updates pricing preferences for multiple listings in one request.
Returns status 207 if some updates failed, 424 if all updates failed.
All fields are optional; only provided fields will be updated. This partial-update
behavior applies at the top level only — omitting a field (e.g. minimum_stay_rules_v3)
leaves it unchanged, but providing a field that holds an array of rules
(e.g. minimum_price_rules_v3) will completely replace the existing rule set
for that field; individual rules within an array cannot be merged or patched.
Always fetch the current preferences before writing and include every rule you
wish to retain — any rules omitted from an array will be permanently deleted.
| channel required | string Channel name the listings are on (the |
required | Array of objects |
{- "listing_preferences": [
- {
- "listing_id": "string",
- "automatic_rate_posting_enabled": true,
- "base_price": 1,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true
}
]
}{- "updated_preferences": [
- {
- "listing_id": 0,
- "partner_listing_id": "string",
- "currency": "string",
- "automatic_rate_posting_enabled": true,
- "base_price": 0,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true,
- "update_from": "string",
- "update_from_id": 0,
- "created_at": "string",
- "updated_at": "string",
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}, - "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}
]
}| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "listing_id": 0,
- "partner_listing_id": "string",
- "currency": "string",
- "automatic_rate_posting_enabled": true,
- "base_price": 0,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true,
- "update_from": "string",
- "update_from_id": 0,
- "created_at": "string",
- "updated_at": "string",
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}, - "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}Updates pricing preferences for a listing.
All fields are optional; only provided fields will be updated. This partial-update
behavior applies at the top level only — omitting a field (e.g. minimum_stay_rules_v3)
leaves it unchanged, but providing a field that holds an array of rules
(e.g. minimum_price_rules_v3) will completely replace the existing rule set
for that field; individual rules within an array cannot be merged or patched.
Always fetch the current preferences before writing and include every rule you
wish to retain — any rules omitted from an array will be permanently deleted.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| automatic_rate_posting_enabled | boolean Whether Wheelhouse automatically posts its price recommendations to the channel calendar. When |
| base_price | integer or null >= 1 The manually set base price. If set, overrides Wheelhouse's data-driven recommendation. Must be a whole number of at least 1. |
| base_price_adjustment | number or null A percentage adjustment to the Wheelhouse recommended base price. Only used if |
| monthly_discount | integer or null Default: 0 Monthly discount percentage as an integer in the range 0–100 (e.g. |
| weekly_discount | integer or null Default: 0 Weekly discount percentage as an integer in the range 0–100 (e.g. |
| nickname | string or null Listing nickname. Overrides the listing's default nickname. |
object or null UI: 'Last minute' — Last-minute discount configuration. | |
object or null UI: 'Far future' — Far-future premium configuration. | |
object or null UI: 'Seasonality' — Seasonality adjustment configuration. | |
object or null Day-of-week pricing factor configuration. | |
object or null Gap night pricing strategy (UI: 'Gaps & Adjacencies' in the Pricing Engine panel). Controls the price multiplier for
gap nights between bookings. When | |
Array of any (integer_calendar_rule) Default: [] UI: 'Minimum stays' — minimum stay rules. The | |
| min_stays_enabled | boolean Whether minimum stay rules are enabled. |
Array of any Default: [] UI: 'Minimum prices' — Minimum price rules. Valid rule types: | |
Array of any Default: [] UI: 'Maximum prices' — Maximum price rules. Valid rule types: | |
object or null Check-in/check-out rule configuration identifier. | |
object Default: {"active":false,"weekly_rules":[],"monthly_rules":[],"rules":{}} Rule-based long-term discount configuration. | |
object or null Default: {} Occupancy pacing configuration. When | |
Array of any Default: [] Demand sensitivity rules. Valid rule types: | |
Array of any Default: [] Historical anchoring rules. Valid rule types: | |
Array of objects (custom_date_range) Default: [] Represents an Event or Season entry used by the Wheelhouse Events & Seasons feature.
Calendar rules reference these entries by Each listing stores its own copy of every Event or Season it belongs to. Entries for the
same event or season share the same To safely modify an event or season's definition (dates or name) on one listing without
affecting others, omit the A new | |
| min_min_price | integer Default: 0 UI: 'Absolute minimum price' — Hard lower bound that overrides all pricing rules. No recommended price will fall below this value regardless of any rule configuration. Distinct from a |
| min_min_stay | integer Default: 0 UI: 'Absolute minimum stay' — Hard lower bound that overrides all minimum stay rules. No minimum stay will be set below this value regardless of any rule configuration. Distinct from both a |
| apply_gap_night_rules_to_overrides | boolean UI: 'Apply Gap Night Rules to Overrides' — When |
{- "automatic_rate_posting_enabled": true,
- "base_price": 1,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true
}{- "listing_id": 0,
- "partner_listing_id": "string",
- "currency": "string",
- "automatic_rate_posting_enabled": true,
- "base_price": 0,
- "base_price_adjustment": 0,
- "monthly_discount": 0,
- "weekly_discount": 0,
- "nickname": "string",
- "last_minute_discount": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "far_future_premium": {
- "type": "CON",
- "rules": [
- {
- "type": "time_based",
- "days_after": 0,
- "days_before": 0,
- "months": [
- 1
], - "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "seasonality_adjustment": {
- "type": "CON",
- "rules": [
- {
- "type": "seasonal",
- "id": 0,
- "priority": 0,
- "day_of_week_values": [
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0
], - "value": 0
}
]
}, - "day_of_week": {
- "type": "CON",
- "rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "gap_night": {
- "custom": [
- {
- "adjacent": "left",
- "adjustment": 0,
- "day_of_week": [
- 6
], - "gap": 0
}
], - "type": "CON"
}, - "minimum_stay_rules_v3": [ ],
- "min_stays_enabled": true,
- "minimum_price_rules_v3": [ ],
- "maximum_price_rules_v3": [ ],
- "checkin_checkout": {
- "active": true,
- "auto_adjust": true,
- "check_in_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
], - "check_out_rules": [
- {
- "type": "global",
- "priority": 0,
- "value": 0
}
]
}, - "long_term_discounts": {
- "active": false,
- "weekly_rules": [ ],
- "monthly_rules": [ ],
- "rules": { }
}, - "occupancy_pacing": { },
- "demand_sensitivity_rules": [ ],
- "historical_anchoring_rules": [ ],
- "custom_date_ranges": [ ],
- "min_min_price": 0,
- "min_min_stay": 0,
- "apply_gap_night_rules_to_overrides": true,
- "update_from": "string",
- "update_from_id": 0,
- "created_at": "string",
- "updated_at": "string",
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}, - "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}Copies the preferences (and optionally custom rates) from a source listing to the target listing. This is a destructive action — it will overwrite the target listing's existing preferences.
The source listing is identified in the request body by copy_preferences_from. The target listing is identified by the listing_id path parameter.
| listing_id required | string The channel's unique listing identifier of the target listing (the one to copy preferences to), or its Wheelhouse listing ID when the top-level |
| copy_custom_rates | boolean Default: true If true, also copies the source listing's custom rates to the target. |
| channel required | string Channel name the target listing is on (see return value of the /listings endpoint), or the literal |
required | object Identifies the source listing to copy preferences from. |
{- "copy_custom_rates": true,
- "channel": "string",
- "copy_preferences_from": {
- "channel": "string",
- "listing_id": "string"
}
}{- "warnings": [
- {
- "setting": "checkin_checkout",
- "reason": "not_supported_by_channel",
- "message": "string",
- "attributes": [
- "string"
]
}
]
}Updates one of the following settings to a preset level (conservative/recommended/aggressive), or toggles automatic rate posting on/off.
| Setting | Accepted parameters |
|---|---|
base_price_adjustment |
type: CON, REC, or AGG |
seasonality_adjustment |
type: CON, REC, or AGG |
last_minute_discount |
type: CON, REC, or AGG |
far_future_premium |
type: CON, REC, or AGG |
automatic_rate_posting |
enabled: true or false |
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| setting required | string Enum: "base_price_adjustment" "seasonality_adjustment" "last_minute_discount" "far_future_premium" "automatic_rate_posting" The setting to update. |
| channel required | string Channel name the listing is on (the |
| type | string Enum: "CON" "REC" "AGG" The preset level to apply. Required for all settings except |
| enabled | boolean The enabled state. Required for |
{- "type": "CON",
- "enabled": true
}{- "error": "API token is at rate limit"
}This endpoint can be used to fetch weekly and monthly discounts set up through Wheelhouse for a listing.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "weekly_discount": 0,
- "monthly_discount": 0
}Returns a list of recent change events for the listing, most recent first. Despite sitting under /preferences, the changelog is not limited to preference changes: it is the single history of everything recorded against the listing. It covers changes to the pricing settings, prices posted to the channel and any post or calendar sync that failed, custom rates added, split or removed, a change of pricing engine, and reservations imported for the listing. Read event on each entry to tell them apart. Custom rate history is therefore read from here rather than from the Custom Rates endpoints, which report the rates currently in force.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> Start of the date range to retrieve changes for. Defaults to 30 days ago. Values earlier than 90 days in the past are clamped to 90 days ago (no error is returned). |
| end_date | string <date> End of the date range to retrieve changes for. Defaults to tomorrow. Clamped to the range [ |
{- "events": [
- {
- "time": "2019-08-24T14:15:22Z",
- "source": "string",
- "event": "string",
- "status": "string",
- "msg": "string"
}
]
}Calendar rules are scoped overrides stored on preference settings such as minimum stay, min/max price, and discount configurations. When the pricing engine evaluates a date, it finds the highest-priority rule whose conditions match that date and applies its value. Rules that do not match that date are skipped; if no rule matches, the engine falls back to a default or applies no constraint.
Each rule has a type that determines its default priority. Higher priority overrides lower priority when multiple rules match the same date. The priority field is assigned automatically by the server — any value submitted in a request body is ignored.
| Priority | Rule type(s) | Scope |
|---|---|---|
| 1 | global |
Whole calendar — at most one per rule set, applies to every date |
| 2 | day_of_week, monthly |
Weekday pattern or specific calendar month(s) |
| 3 | time_based |
Booking window relative to today (days_before / days_after) |
| 4 | seasonal |
Named seasonal date range (references custom_date_ranges) |
| 5 | event |
Named event date range (references custom_date_ranges) |
| 6 | adjacency / one_sided_gap |
Adjacent-gap nights — minimum_stay_rules_v3 only |
| 7 | gap |
Gap-night minimum stay — minimum_stay_rules_v3 only |
| 8 | custom |
Fixed calendar date range (start_date / end_date) |
custom rules always win. global is the catch-all baseline that every other rule type can override.
When multiple rules match the same date, the highest-priority rule wins (largest priority number). Within the same rule type, the engine applies additional specificity ordering:
time_based — a narrower booking window (smaller days_before) overrides a wider one on the same date.custom — a one-time range (yearly: false) overrides a recurring range (yearly: true) on the same dates.day_of_week and monthly — when multiple rules of the same type cover the same date, the one with the more specific condition (e.g. with months set vs. without) takes precedence.Rules can carry either a scalar value (applies to every matching date) or day_of_week_values (a 7-element array, index 0 = Sunday). A null element in day_of_week_values means the rule does not apply for that specific weekday — the engine falls through to the next applicable rule in the priority hierarchy for that day.
seasonal and event rules reference a custom_date_ranges entry by id. The date window (start, end) is defined in that entry; the rule sets the value to apply over the window. A new entry and a rule referencing it can be sent in the same PUT request — manually assign the id on the new entry so the referencing rule can use it in the same payload.
| Setting | Supported rule types |
|---|---|
last_minute_discount |
time_based, seasonal, event, monthly, day_of_week, custom |
far_future_premium |
time_based, seasonal, event, monthly, day_of_week, custom |
seasonality_adjustment |
seasonal, event, monthly |
day_of_week |
global, time_based, seasonal, event, monthly, day_of_week, custom |
minimum_stay_rules_v3 |
global, time_based, seasonal, event, monthly, day_of_week, custom, gap, adjacency |
minimum_price_rules_v3 |
global, time_based, seasonal, event, monthly, day_of_week, custom |
maximum_price_rules_v3 |
global, time_based, seasonal, event, monthly, day_of_week, custom |
checkin_checkout > check_in_rules |
global, time_based, seasonal, event, monthly, day_of_week, custom |
checkin_checkout > check_out_rules |
global, time_based, seasonal, event, monthly, day_of_week, custom |
demand_sensitivity_rules |
global, time_based, seasonal, event, monthly, day_of_week, custom |
historical_anchoring_rules |
global, time_based, seasonal, event, monthly, day_of_week, custom |
Returns all custom rate periods that are currently active and affect future stay dates.
Expired rate periods (those whose expires_at timestamp has passed) are excluded.
This is the state of the listing's custom rates now, not their history. For a record of
when custom rates were added, split or removed, and by whom, read the listing's
changelog and look for Custom rates events.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
[- {
- "id": 0,
- "listing_id": 0,
- "rate_type": "fixed",
- "currency": "string",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "sunday": 0,
- "monday": 0,
- "tuesday": 0,
- "wednesday": 0,
- "thursday": 0,
- "friday": 0,
- "saturday": 0,
- "created_user_id": 0,
- "split_user_id": 0,
- "expires_at": "2019-08-24T14:15:22Z",
- "valid_until": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]Creates or replaces a custom rate for a date range. Setting a fixed rate applies an
absolute nightly price; setting an adjustment rate applies a percentage multiplier to
the Wheelhouse recommendation. For adjustment rates, per-day values are percentages
where 100 = no adjustment, 110 = +10%, and 90 = −10%.
If the specified date range overlaps an existing custom rate, the existing rate is shortened or split so the new rate takes precedence for the overlapping dates. Custom rates are not stacked — a new adjustment rate replaces rather than compounds with any existing adjustment for the same dates. To combine adjustments, compute the target multiplier explicitly and submit the combined value.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date required | string <date> The first date of the custom rate period (YYYY-MM-DD). |
| end_date required | string <date> The last date of the custom rate period (YYYY-MM-DD). |
| rate_type required | string Enum: "fixed" "adjustment" The type of custom rate.
Minimum price interactions: Fixed rates are constrained only by Read-side representation: When reading prices via |
| currency | string The ISO-4217 3-letter currency code. Required for |
| sunday | integer >= 1 Price or adjustment value for Sundays. |
| monday | integer >= 1 Price or adjustment value for Mondays. |
| tuesday | integer >= 1 Price or adjustment value for Tuesdays. |
| wednesday | integer >= 1 Price or adjustment value for Wednesdays. |
| thursday | integer >= 1 Price or adjustment value for Thursdays. |
| friday | integer >= 1 Price or adjustment value for Fridays. |
| saturday | integer >= 1 Price or adjustment value for Saturdays. |
| expires_at | string <date-time> When the custom rate expires (ISO-8601). Once past this timestamp the rate is no longer applied. Omit to create a rate that never expires. |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "rate_type": "fixed",
- "currency": "string",
- "sunday": 1,
- "monday": 1,
- "tuesday": 1,
- "wednesday": 1,
- "thursday": 1,
- "friday": 1,
- "saturday": 1,
- "expires_at": "2019-08-24T14:15:22Z"
}{- "id": 0,
- "listing_id": 0,
- "rate_type": "fixed",
- "currency": "string",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "sunday": 0,
- "monday": 0,
- "tuesday": 0,
- "wednesday": 0,
- "thursday": 0,
- "friday": 0,
- "saturday": 0,
- "created_user_id": 0,
- "split_user_id": 0,
- "expires_at": "2019-08-24T14:15:22Z",
- "valid_until": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Removes all custom rates overlapping the specified date range. If a custom rate period extends beyond the deleted range on one side only, it is truncated to the non-overlapping portion. If the deleted range falls in the middle of an existing rate period, that period is split into two — one before and one after the deleted range. The deleted dates revert to the Wheelhouse recommended price.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date required | string <date> The start date of the range to delete (YYYY-MM-DD). This date is inclusive. |
| end_date required | string <date> The end date of the range to delete (YYYY-MM-DD). This date is inclusive. |
{- "error": "API token is at rate limit"
}Creates or replaces multiple custom rates in a single request. Partially successful
requests return status 207; fully failed requests return 424.
For adjustment rates, per-day values are percentages where 100 = no adjustment,
110 = +10%, and 90 = −10%.
If a specified date range overlaps an existing custom rate, the existing rate is shortened or split so the new rate takes precedence for the overlapping dates. Custom rates are not stacked — a new adjustment rate replaces rather than compounds with any existing adjustment for the same dates. To combine adjustments, compute the target multiplier explicitly and submit the combined value.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
required | Array of objects (custom_rate_input) |
{- "custom_rates": [
- {
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "rate_type": "fixed",
- "currency": "string",
- "sunday": 1,
- "monday": 1,
- "tuesday": 1,
- "wednesday": 1,
- "thursday": 1,
- "friday": 1,
- "saturday": 1,
- "expires_at": "2019-08-24T14:15:22Z"
}
]
}{- "updated_custom_rates": [
- {
- "id": 0,
- "listing_id": 0,
- "rate_type": "fixed",
- "currency": "string",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "sunday": 0,
- "monday": 0,
- "tuesday": 0,
- "wednesday": 0,
- "thursday": 0,
- "friday": 0,
- "saturday": 0,
- "created_user_id": 0,
- "split_user_id": 0,
- "expires_at": "2019-08-24T14:15:22Z",
- "valid_until": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Removes custom rates for multiple date ranges in a single request. Partially successful requests return status 207; fully failed requests return 424.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel | string Channel name the listing is on (the |
required | Array of objects |
{- "channel": "string",
- "delete_ranges": [
- {
- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}
]
}{- "errors": [
- {
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "http_code": 0,
- "message": "string"
}
]
}Returns a list of reservations for a listing.
Deriving pickup metrics: Use date_filter_type=booked_at to filter by booking date rather than stay date:
end_date − start_date (in days) across returned reservations.| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> Filter start date (YYYY-MM-DD). Behavior depends on
|
| end_date | string <date> Filter end date (YYYY-MM-DD). Behavior depends on
|
| date_filter_type | string Default: "stay_date" Enum: "stay_date" "booked_at" Controls which date field is used for filtering:
|
| per_page | integer [ 1 .. 100 ] Default: 50 Number of reservations per page. |
| page | integer Page number to retrieve. |
| offset | integer Number of items to skip before starting to collect the result set. |
[- {
- "id": "string",
- "status": "string",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "booked_at": "2019-08-24T14:15:22Z",
- "canceled_at": "2019-08-24T14:15:22Z",
- "num_guests": 0,
- "currency": "string",
- "total_price": 0,
- "nightly_subtotal": 0,
- "extra_guest": 0,
- "security_deposit": 0,
- "extras": 0,
- "taxes": 0,
- "confirmation_code": "string",
- "source_name": "string",
- "comments": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
[- {
- "id": 0,
- "name": "string",
- "description": "string",
- "type": "string"
}
]Adds (or overwrites) tags on a listing. If overwrite is false, provided tags are merged with existing tags. If overwrite is true, existing tags are replaced and all tags that are not in the list are deleted.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| names required | Array of strings Array of tag names to add (or set if |
| overwrite | boolean Default: false If true, replaces all existing tags with the provided list. If false (default), merges with existing tags. |
{- "names": [
- "string"
], - "overwrite": false
}[- {
- "id": 0,
- "name": "string",
- "description": "string",
- "type": "string"
}
]Flags are system-managed tags that Wheelhouse sets automatically on listings to convey internal state or signals. Unlike user-defined tags, flags are read-only and cannot be modified via the API.
Returns system-managed flags (as opposed to user-defined tags) associated with the listing.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
[- {
- "name": "string",
- "description": "string"
}
]Notes are user-created annotations on a listing, optionally tied to a date range, a settings category, and a reminder. Use these endpoints to fetch, create, update, and delete the notes of a listing. Notes can be active or archived; deleting a note removes it permanently — deleted notes are no longer returned by the API and cannot be restored.
Returns the notes of the listing, most recently updated first. Deleted notes are not included. Optionally restrict the response to notes whose date range overlaps a given date range — start_date and end_date must be provided together.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> Only include notes whose date range overlaps the given range (YYYY-MM-DD). Must be provided together with |
| end_date | string <date> Only include notes whose date range overlaps the given range (YYYY-MM-DD). Must be provided together with |
[- {
- "id": 0,
- "description": "string",
- "category": [
- "base_price"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "remind_by": "2019-08-24",
- "repeat_by": "daily",
- "status": "active",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]Creates a note on the listing. All fields are optional — provide a description, an optional stay date range (start_date/end_date), settings categories, and an optional reminder (remind_by with repeat_by).
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| description | string The note text. |
| category | Array of strings The settings categories the note relates to. See the |
| start_date | string <date> First stay date the note applies to (YYYY-MM-DD). Must be provided together with |
| end_date | string <date> Last stay date the note applies to (YYYY-MM-DD). Must be provided together with |
| remind_by | string <date> Date of the note's reminder (YYYY-MM-DD). Must be provided together with |
| repeat_by | string Enum: "daily" "weekly" "monthly" "does_not_repeat" How the reminder repeats. Must be provided together with |
| status | string Enum: "active" "archived" The note status. Defaults to |
{- "description": "string",
- "category": [
- "string"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "remind_by": "2019-08-24",
- "repeat_by": "daily",
- "status": "active"
}{- "id": 0,
- "description": "string",
- "category": [
- "base_price"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "remind_by": "2019-08-24",
- "repeat_by": "daily",
- "status": "active",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Updates the given fields of a note. Fields that are not provided are left unchanged. Set status to archived to archive a note, or back to active to restore it.
Note: it is not currently possible to clear an optional field once set (for example, removing an existing date range or reminder). Omitting a field in the request body leaves the current value in place; there is no way to unset start_date/end_date or remind_by/repeat_by via this endpoint.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| note_id required | integer The Wheelhouse internal note ID. |
| channel required | string Channel name the listing is on (the |
| description | string The note text. |
| category | Array of strings The settings categories the note relates to. See the |
| start_date | string <date> First stay date the note applies to (YYYY-MM-DD). Must be provided together with |
| end_date | string <date> Last stay date the note applies to (YYYY-MM-DD). Must be provided together with |
| remind_by | string <date> Date of the note's reminder (YYYY-MM-DD). Must be provided together with |
| repeat_by | string Enum: "daily" "weekly" "monthly" "does_not_repeat" How the reminder repeats. Must be provided together with |
| status | string Enum: "active" "archived" The note status. |
{- "description": "string",
- "category": [
- "string"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "remind_by": "2019-08-24",
- "repeat_by": "daily",
- "status": "active"
}{- "id": 0,
- "description": "string",
- "category": [
- "base_price"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "remind_by": "2019-08-24",
- "repeat_by": "daily",
- "status": "active",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Deletes the note. Deletion is permanent — the note is no longer returned by the API and cannot be restored.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| note_id required | integer The Wheelhouse internal note ID. |
| channel required | string Channel name the listing is on (the |
{- "error": "API token is at rate limit"
}Fetch the price calendar for a listing. The calendar reflects current prices, availability, and booking state for each stay date.
Returns the price calendar for a single listing. Each entry represents one stay date and includes the price, availability, and booking state.
The data reflects the current state of the calendar as of the time of the request:
Defaults to today through the maximum calendar horizon (1.5 years) when start_date and end_date are omitted. The total date range may not exceed 3 years.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> First stay date to include (YYYY-MM-DD). Defaults to today. |
| end_date | string <date> Last stay date to include (YYYY-MM-DD). Defaults to the maximum calendar horizon (1.5 years from today). The total range ( |
[- {
- "stay_date": "2019-08-24",
- "price": 0,
- "currency": "string",
- "is_available": true,
- "is_booked": true,
- "block_time": "2019-08-24",
- "reservation_id": 0,
- "unit_number": 0,
- "created_at": "2019-08-24T14:15:22Z"
}
]Returns the last price posted to the channel for each stay date in the requested range.
block_time (when the booking was recorded), reflecting the price that was live when the booking came in.Dates with no posting history return null for last_posted_price.
Defaults to today through the maximum calendar horizon (1.5 years) when start_date and end_date are omitted. The total date range may not exceed 3 years.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> First stay date to include (YYYY-MM-DD). Defaults to today. |
| end_date | string <date> Last stay date to include (YYYY-MM-DD). Defaults to the maximum calendar horizon (1.5 years from today). The total range ( |
[- {
- "stay_date": "2019-08-24",
- "unit_number": 0,
- "last_posted_price": 0
}
]Returns a history of price postings and calendar state snapshots for a specific stay date.
posted_prices — each entry records a price that Wheelhouse posted to the channel for this date, in chronological order.calendar_snapshots — historical snapshots of the calendar day's state (availability, price, booking, etc.) over time.Requires a Pro tier listing. Returns 402 if the feature is not available. The maximum lookback window is 180 days.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| stay_date required | string <date> The stay date to retrieve history for (YYYY-MM-DD). |
{- "stay_date": "2019-08-24",
- "posted_prices": [
- {
- "posted_at": "2019-08-24T14:15:22Z",
- "posted_price": 0
}
], - "calendar_snapshots": [
- {
- "price": 0,
- "currency": "string",
- "is_available": true,
- "is_booked": true,
- "block_time": "2019-08-24",
- "reservation_id": 0,
- "unit_number": 0,
- "created_at": "2019-08-24T14:15:22Z"
}
]
}Returns a per-date fee multiplier derived from the listing's estimated fee setting. Multiply any nightly price by fee_multiplier to obtain the fee-inclusive price. A fee_multiplier of 1.0 means no fee adjustment is configured.
Currently the multiplier is uniform across all dates. The per-date shape is intentional — future releases will allow fee variation by date range or season, and the response format will remain compatible.
Defaults to today through the maximum calendar horizon (1.5 years) when start_date and end_date are omitted. The total date range may not exceed 3 years.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> First stay date to include (YYYY-MM-DD). Defaults to today. |
| end_date | string <date> Last stay date to include (YYYY-MM-DD). Defaults to the maximum calendar horizon (1.5 years from today). The total range ( |
[- {
- "stay_date": "2019-08-24",
- "fee_multiplier": 0
}
]Returns the per-date minimum stay derived from the listing's minimum stay rules for a given date range. One entry is returned for each date in the range.
A null value for min_stay means no specific rule covers that date.
Defaults to today through the maximum calendar horizon (1.5 years) when start_date and end_date are omitted. The total date range may not exceed 3 years.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
| start_date | string <date> First stay date to include (YYYY-MM-DD). Defaults to today. |
| end_date | string <date> Last stay date to include (YYYY-MM-DD). Defaults to the maximum calendar horizon (1.5 years from today). The total range ( |
[- {
- "stay_date": "2019-08-24",
- "min_stay": 0
}
]Portfolio segments group listings by filter criteria. The filter_backend field
is the core of a segment — it defines which listings belong to it.
Use POST /segments to create a segment, PUT /segments/{segment_id} to update
one, GET /segments to list all segments for the authenticated user,
GET /segments/{segment_id}/listings to retrieve the listings matched by a
segment's filter, and GET /segments/{segment_id}/aggregated_metrics to fetch
aggregated performance metrics for those listings.
See the filter_backend_object schema for a full reference of available filter
keys, operator suffixes, and value formats.
Returns all portfolio segments for the authenticated user. Segments are used in the Wheelhouse UI to group listings by filter criteria; this endpoint provides read-only access to the segment list.
[- {
- "id": 0,
- "name": "string",
- "description": "string",
- "filter_backend": { },
- "is_default": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]Creates a new portfolio segment owned by the authenticated user.
| name required | string Name of the segment. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description | string Optional description. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
object (filter_backend_object) A map that controls which listings belong to a segment. Keys are listing attribute paths with optional operator suffixes; values are the match criteria. All entries are ANDed — a listing must satisfy every condition to be included. Structure: Boolean parametersAccept
Numeric range parametersEach base key supports six operator suffixes:
Performance stats follow the pattern Enumeration parametersThree operator suffixes:
String match parametersTwo operator suffixes:
Tag parametersFilter by Wheelhouse tag IDs (integers). Four operator suffixes:
To combine multiple independent tag conditions in one object, append any unique
identifier after the suffix — the system strips it before evaluating. Example:
Date range parametersSix operator suffixes, same as numeric range. Values are either an ISO 8601 date
string (
Membership parameters
Geographic parameter
Example
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_default | boolean Set as the default segment. Any existing default is cleared. |
{- "name": "string",
- "description": "string",
- "filter_backend": { },
- "is_default": true
}{- "id": 0,
- "name": "string",
- "description": "string",
- "filter_backend": { },
- "is_default": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Updates the name, description, and/or default status of an existing portfolio segment. All fields are optional; omitted fields are left unchanged.
| segment_id required | integer The Wheelhouse internal segment ID. |
| name | string New name for the segment. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description | string New description for the segment. Omit to leave unchanged. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
object (filter_backend_object) A map that controls which listings belong to a segment. Keys are listing attribute paths with optional operator suffixes; values are the match criteria. All entries are ANDed — a listing must satisfy every condition to be included. Structure: Boolean parametersAccept
Numeric range parametersEach base key supports six operator suffixes:
Performance stats follow the pattern Enumeration parametersThree operator suffixes:
String match parametersTwo operator suffixes:
Tag parametersFilter by Wheelhouse tag IDs (integers). Four operator suffixes:
To combine multiple independent tag conditions in one object, append any unique
identifier after the suffix — the system strips it before evaluating. Example:
Date range parametersSix operator suffixes, same as numeric range. Values are either an ISO 8601 date
string (
Membership parameters
Geographic parameter
Example
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| is_default | boolean Set as the default segment. Any existing default is cleared. |
{- "name": "string",
- "description": "string",
- "filter_backend": { },
- "is_default": true
}{- "id": 0,
- "name": "string",
- "description": "string",
- "filter_backend": { },
- "is_default": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Returns the listings that belong to the given portfolio segment. The segment's filter criteria are applied to the user's portfolio — for an RM API key that includes listings shared with the user to manage, not just listings they own (see include_managed_listings). Supports pagination and optional exclusion of inactive listings.
| segment_id required | integer The Wheelhouse internal segment ID. |
| exclude_inactive | boolean Default: true Exclude inactive listings from the response. Defaults to true. |
| per_page | integer [ 1 .. 100 ] Default: 50 Number of listings per page. |
| page | integer Page number to retrieve. |
| offset | integer Number of items to skip before starting to collect the result set. |
| include_managed_listings | boolean Default: true When true (default for RM API keys), the segment's filter is evaluated against listings the user manages for another Wheelhouse account (valid shared-access grants) as well as listings they own. Set to false to match only owned listings. Channel integration keys default to false, since they act on the one account they connected. |
[- {
- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}
]Returns monthly performance metrics aggregated across the listings matched by the segment's filter. For an RM API key the filter is evaluated against listings shared with the user to manage as well as listings they own (see include_managed_listings). Monetary values are converted to the requested currency. Because a segment has no currency of its own, the default is the currency of the most common market among the segment's listings (falling back to USD).
| segment_id required | integer The Wheelhouse internal segment ID. |
| currency | string ISO-4217 3-letter currency code to convert monetary metrics to. Defaults to the currency of the most common market among the segment's listings. |
| dates | Array of strings <date> [ items <date > ] Restrict the response to periods starting on these dates (first of month, YYYY-MM-DD). Send as |
| include_managed_listings | boolean Default: true When true (default for RM API keys), the segment's filter is evaluated against listings the user manages for another Wheelhouse account (valid shared-access grants) as well as listings they own. Set to false to match only owned listings. Channel integration keys default to false, since they act on the one account they connected. |
{- "data": [
- {
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "nights_percent_open": 0,
- "revenue": 0,
- "adr": 0,
- "asking_rate": 0,
- "revpar": 0,
- "revpar_adjusted": 0,
- "revenue_available": 0,
- "revenue_blocked": 0,
- "lead_time": 0,
- "length_of_stay": 0,
- "nights_available": 0,
- "nights_blocked": 0,
- "nights_booked": 0,
- "nights_bookable": 0,
- "nights_calendar": 0,
- "count_bookings": 0
}
], - "currency": "string"
}Access aggregated market-level data for the markets in which the authenticated user has at least one Pro tier listing. Use these endpoints to retrieve time-series metrics (e.g. occupancy, asking rate, RevPAR) and metric distributions across a market for a given month. Results can be filtered by bedroom count, property type, and performance tier.
Returns all active Wheelhouse markets which the authenticated user has at least one Pro tier listing in for the given country.
Each market includes its geographic shape and the postal codes it covers.
| country_code required | string ISO-3166 2-letter country code (e.g. |
[- {
- "market_id": 0,
- "market_name": "string",
- "geometry": [
- [
- [
- 0,
- 0
]
]
], - "postal_codes": [
- {
- "code": "string",
- "latlong": "string",
- "geometry": "string"
}
]
}
]Returns daily time-series data for one or more market-level metrics over a date range. RM API users can only access markets in which they have at least one Pro tier listing.
Available metrics: asking_rate_w_fees, occupancy, occupancy_adjusted, adr_w_fees, lead_time, revpar_adjusted_w_fees, revpar_w_fees, revenue_w_fees, nights_bookable.
| market_id required | integer The Wheelhouse internal market ID (from |
| metric | Array of strings Items Enum: "occupancy" "occupancy_adjusted" "nights_bookable" "asking_rate_w_fees" "adr_w_fees" "lead_time" "revpar_adjusted_w_fees" "revpar_w_fees" "revenue_w_fees" Metrics to include. Defaults to all metrics. Send as |
| start_date | string <date> Start of the date range (YYYY-MM-DD). Defaults to today. Must be within 3 years in the past and 1 year in the future. |
| end_date | string <date> End of the date range (YYYY-MM-DD). Defaults to 1 year from today. Must be after |
| performance | string Enum: "low" "average" "high" Filter to a performance tier. Omit to include all tiers. |
| bedrooms | string Enum: "0" "1" "2" "3" "4+" Filter to listings with this bedroom count. Omit to include all bedroom counts. |
| property_type | string Enum: "apartment" "bnb" "boat" "bus" "cabin" "camper" "camping" "castle" "holiday_home" "hostel" "hotel" "house" "houseboat" "island" "mill" "other" "room" "shared" "tower" Filter to a property type. Omit to include all property types. |
{- "currency": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "data": [
- {
- "stay_date": "2019-08-24",
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "nights_bookable": 0,
- "asking_rate_w_fees": 0,
- "adr_w_fees": 0,
- "lead_time": 0,
- "revpar_adjusted_w_fees": 0,
- "revpar_w_fees": 0,
- "revenue_w_fees": 0
}
]
}Returns histogram distributions for one or more market-level metrics for a given calendar month. RM API users can only access markets in which they have at least one Pro tier listing.
Available metrics: occupancy, occupancy_adjusted, asking_rate_w_fees, adr_w_fees, lead_time, revpar_adjusted_w_fees, revpar_w_fees, length_of_stay.
| market_id required | integer The Wheelhouse internal market ID (from |
| metric | Array of strings Items Enum: "occupancy" "occupancy_adjusted" "asking_rate_w_fees" "adr_w_fees" "lead_time" "revpar_adjusted_w_fees" "revpar_w_fees" "length_of_stay" Metrics to include. Defaults to all metrics. Send as |
| month | string <date> The month to retrieve distributions for (any date within the month, YYYY-MM-DD). Defaults to the start of the current month. |
| performance | string Enum: "low" "average" "high" Filter to a performance tier. Omit to include all tiers. |
| bedrooms | string Enum: "0" "1" "2" "3" "4+" Filter to listings with this bedroom count. Omit to include all bedroom counts. |
| property_type | string Enum: "apartment" "bnb" "boat" "bus" "cabin" "camper" "camping" "castle" "holiday_home" "hostel" "hotel" "house" "houseboat" "island" "mill" "other" "room" "shared" "tower" Filter to a property type. Omit to include all property types. |
{- "currency": "string",
- "month": "2019-08-24",
- "updated_at": "2019-08-24T14:15:22Z",
- "data": {
- "property1": [
- {
- "bucket_min_incl": 0,
- "bucket_max_excl": 0,
- "probability": 0,
- "percentile": 0
}
], - "property2": [
- {
- "bucket_min_incl": 0,
- "bucket_max_excl": 0,
- "probability": 0,
- "percentile": 0
}
]
}
}Daily market and neighborhood price data for a listing's location. The neighborhood data reflects the local cluster of comparable properties near the listing (same bedroom count, same geographic cluster), providing context for competitive pricing.
Additional data sources — including market-wide aggregates and dynamic comparison sets — will be added here in future releases.
Returns a daily time series of neighborhood price data for the listing's local cluster — a geographic group of comparable properties with the same bedroom count near the listing.
Each entry includes the median nightly price, the p25 (low_price) and p75 (high_price)
price percentiles, and the number of listings in the cluster for that stay date. All prices
are in the market's native currency, reported in the currency field.
This is the same neighborhood data shown in the Wheelhouse pricing chart.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "data": [
- {
- "stay_date": "2019-08-24",
- "median_price": 0,
- "low_price": 0,
- "high_price": 0,
- "listings_count": 0
}
], - "currency": "string"
}Returns a daily time series of occupancy and booking model data for the listing's local neighborhood cluster. This is the same data used to render the occupancy, expected bookings, and observed bookings series in the Wheelhouse pricing chart.
occupancy — raw occupancy rate (booked nights / calendar nights).adjusted_occupancy — occupancy computed against bookable (unblocked) nights only.expected_bookings — model-predicted booking count for the stay date.expected_bookings_sd — standard deviation of the expected bookings prediction.observed_bookings — actual booking count observed for the stay date.calendar_nights — total calendar nights in the cluster for the stay date.Returns 404 if no neighborhood cluster is found for the listing's location, or if no
occupancy data has been generated for the cluster.
| listing_id required | string The channel's unique listing identifier, or the Wheelhouse listing ID when |
| channel required | string Channel name the listing is on (the |
{- "data": [
- {
- "stay_date": "2019-08-24",
- "occupancy": 0,
- "adjusted_occupancy": 0,
- "expected_bookings": 0,
- "expected_bookings_sd": 0,
- "observed_bookings": 0,
- "calendar_nights": 0
}
]
}Dynamic sets are user-curated sets of comparison listings used to track competitive performance. Use these endpoints to build a set from scratch (search for candidate listings near a location, create a set from them, and upgrade it to paid), list a user's sets, inspect a set's definition and member listings, retrieve aggregated performance metrics, manage which of the user's own listings the set is associated with, and fetch a set's change history, time-series metrics, and metric distributions.
GET /sets returns both free and paid sets; the is_paid field on each set indicates which. Everything involved in building a set works on a free one — creating it, adding and removing its member listings, reviewing them, and managing which of your own listings it is associated with. What the paid plan buys is the set-level analytics computed across the set, including its price calendar. A paid-only endpoint returns 404 Not Found for a free set, which is indistinguishable from a set that does not exist, so check is_paid before calling one.
| Endpoint | Free sets | Paid sets |
|---|---|---|
GET /sets |
✅ | ✅ |
POST /sets |
✅ (creates a free set) | — |
GET /sets/candidates |
✅ (no set required) | ✅ |
GET /sets/{set_id} |
✅ | ✅ |
POST /sets/{set_id}/upgrade |
✅ (this is what upgrades it) | — |
POST /sets/{set_id}/share |
✅ | ✅ |
GET /sets/{set_id}/listings |
✅ | ✅ |
PUT /sets/{set_id}/listings |
✅ | ✅ |
DELETE /sets/{set_id}/listings |
✅ | ✅ |
GET /sets/{set_id}/associated_listings |
✅ | ✅ |
PUT /sets/{set_id}/associated_listings |
✅ | ✅ |
DELETE /sets/{set_id}/associated_listings |
✅ | ✅ |
GET /sets/{set_id}/aggregated_metrics |
❌ 404 | ✅ |
GET /sets/{set_id}/price_calendar |
❌ 404 | ✅ (up to 25 members) |
GET /sets/{set_id}/time_series |
❌ 404 | ✅ |
GET /sets/{set_id}/distribution |
❌ 404 | ✅ |
GET /sets/{set_id}/changelog |
❌ 404 | ✅ |
Upgrade a free set with POST /sets/{set_id}/upgrade, which purchases the paid plan and charges the billable user. Sets the user owns as well as sets shared with the user are included throughout; modifying a shared set requires editor or manager access to it.
Returns all dynamic sets the authenticated user owns or has shared access to, including both free and paid sets. Use the is_paid field to tell them apart — only paid sets expose KPI data, and free sets can be upgraded via POST /sets/{set_id}/upgrade. Results are ordered by most recently updated first and paginated.
Narrow the list with name and kind. Both are optional, and sending both returns only the sets matching each of them.
| name | string Example: name=*Palm Springs* Match sets by name. |
| kind | string Example: kind=competitive Match sets by their |
| per_page | integer [ 1 .. 100 ] Default: 50 Number of sets per page. |
| page | integer Page number to retrieve. |
| offset | integer Number of items to skip before starting to collect the result set. |
[- {
- "id": 0,
- "user_id": 0,
- "name": "string",
- "description": "string",
- "kind": "competitive",
- "currency": "string",
- "is_static": true,
- "is_paid": true,
- "filters": { },
- "boundary": [
- [
- [
- [
- 0,
- 0
]
]
]
], - "listing_counts": {
- "active": 0,
- "hidden": 0,
- "review": 0,
- "removed": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}
]Creates a free dynamic set owned by the authenticated user. Add candidate listings (from GET /sets/candidates) by passing their internal listing_ids in listing_ids; they are added with the active status. The set is created on the free plan — upgrade it with POST /sets/{set_id}/upgrade to access its KPI endpoints.
| name required | string Name of the dynamic set. |
| description | string Optional description of the set. |
| currency | string ISO-4217 3-letter currency code. Defaults to the currency of the most common market among the set's listings. |
| listing_ids | Array of integers Internal listing IDs (the |
{- "name": "string",
- "description": "string",
- "currency": "string",
- "listing_ids": [
- 0
]
}{- "id": 0,
- "user_id": 0,
- "name": "string",
- "description": "string",
- "kind": "competitive",
- "currency": "string",
- "is_static": true,
- "is_paid": true,
- "filters": { },
- "boundary": [
- [
- [
- [
- 0,
- 0
]
]
]
], - "listing_counts": {
- "active": 0,
- "hidden": 0,
- "review": 0,
- "removed": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}Returns market listings near a location, with their trailing-year performance metrics, to choose from when building a dynamic set. Provide either a lat/long/radius (radius in meters) or one or more market_ids. Results are ordered nearest-first (each carries a distance_meters value) and paginated. Pass the returned listing_ids to POST /sets to add them as members. Not tied to a set, so no set plan applies.
| lat | number Latitude of the search center. Must be sent together with long and radius. |
| long | number Longitude of the search center. Must be sent together with lat and radius. |
| radius | integer Search radius in meters. Must be sent together with lat and long. |
| market_ids | Array of integers Restrict candidates to these markets. Provide this or lat/long/radius. |
| min_bedrooms | integer |
| max_bedrooms | integer |
| min_bathrooms | number |
| max_bathrooms | number |
| room_types | Array of strings Items Enum: "apartment" "bnb" "boat" "bus" "cabin" "camper" "camping" "castle" "holiday_home" "hostel" "hotel" "house" "houseboat" "island" "mill" "other" "room" "shared" "tower" Restrict candidates to these normalized room types. |
| min_bookable_nights_0_365 | integer Minimum bookable nights over the next 365 days. |
| min_open_occupancy_0_365 | number Minimum forward-looking adjusted occupancy (0–1). |
| min_open_occupancy_365_0 | number Default: 0.35 Minimum trailing-year adjusted occupancy (0–1). Defaults to 0.35. |
| min_bookable_nights_365_0 | integer Default: 127 Minimum trailing-year bookable nights. Defaults to 127. |
| per_page | integer [ 1 .. 100 ] Default: 50 Number of candidates per page. |
| page | integer Page number to retrieve. |
[- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]Returns detailed information about one dynamic set, including its definition (kind, filters, boundary) and member listing counts per status. Works for free and paid sets.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
{- "id": 0,
- "user_id": 0,
- "name": "string",
- "description": "string",
- "kind": "competitive",
- "currency": "string",
- "is_static": true,
- "is_paid": true,
- "filters": { },
- "boundary": [
- [
- [
- [
- 0,
- 0
]
]
]
], - "listing_counts": {
- "active": 0,
- "hidden": 0,
- "review": 0,
- "removed": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}Purchases the paid Dynamic Sets plan for a free set so its KPI endpoints (aggregated_metrics, time_series, distribution, report) become available. This creates a real paid subscription and charges the billable user's payment method. Only the set's owner or a manager-level collaborator may upgrade a set (editors cannot), and the billable user must have a valid payment method on file. Returns the upgraded set.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
{- "id": 0,
- "user_id": 0,
- "name": "string",
- "description": "string",
- "kind": "competitive",
- "currency": "string",
- "is_static": true,
- "is_paid": true,
- "filters": { },
- "boundary": [
- [
- [
- [
- 0,
- 0
]
]
]
], - "listing_counts": {
- "active": 0,
- "hidden": 0,
- "review": 0,
- "removed": 0
}, - "updated_at": "2019-08-24T14:15:22Z"
}Returns monthly performance metrics aggregated across the active member listings of the set. Monetary values are converted to the requested currency (defaults to the set's currency). Paid sets only. Returns 404 Not Found for a free set — upgrade it first with POST /sets/{set_id}/upgrade.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| currency | string ISO-4217 3-letter currency code to convert monetary metrics to. Defaults to the set's currency. |
| dates | Array of strings <date> [ items <date > ] Restrict the response to periods starting on these dates (first of month, YYYY-MM-DD). Send as |
{- "data": [
- {
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "nights_percent_open": 0,
- "revenue": 0,
- "adr": 0,
- "asking_rate": 0,
- "revpar": 0,
- "revpar_adjusted": 0,
- "revenue_available": 0,
- "revenue_blocked": 0,
- "lead_time": 0,
- "length_of_stay": 0,
- "nights_available": 0,
- "nights_blocked": 0,
- "nights_booked": 0,
- "nights_bookable": 0,
- "nights_calendar": 0,
- "count_bookings": 0
}
], - "currency": "string"
}Returns the member listings of the set with their trailing-year performance metrics, grouped by membership status (active, hidden, review, removed). Monetary metrics are converted to the set's currency. Works for both free and paid sets, so a set can be reviewed before it is upgraded; the same per-listing metrics are also available ungated via GET /sets/candidates.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
{- "active": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "hidden": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "review": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "removed": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
]
}Adds the given listings to the set as members — the comparison listings the set is built from. Identify them by the internal listing_id values returned by GET /sets/candidates; only listings that are eligible comparison candidates can be added. Returns the set's member listings after the change, in the same shape as GET /sets/{set_id}/listings. Requires editor or manager access to the set when the set is shared. Works for free and paid sets. This is an upsert: a listing already in the set keeps its single membership and takes the requested status, so repeating an identical call leaves the set in the same state.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| listing_ids required | Array of integers <= 500 items Internal listing IDs to add as members — the |
| status | string Default: "active" Enum: "active" "hidden" "review" "removed" Membership status to add the listings with. Defaults to |
{- "listing_ids": [
- 0
], - "status": "active"
}{- "active": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "hidden": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "review": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "removed": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
]
}Removes the given listings from the set's membership. Identify them by their internal listing_id. Returns the set's member listings after the change, in the same shape as GET /sets/{set_id}/listings. Requires editor or manager access to the set when the set is shared. Works for free and paid sets. Note that on a filter-based (non-static) set, membership is derived from the set's own filters, so removed members may be restored by the next sync — the same behaviour as the Wheelhouse app.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| listing_ids required | Array of integers <= 500 items Internal listing IDs to remove from the set. IDs that are not members are ignored. At most 500 per request. |
{- "listing_ids": [
- 0
]
}{- "active": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "hidden": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "review": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
], - "removed": [
- {
- "listing_id": 0,
- "title": "string",
- "source": "string",
- "url": "string",
- "thumb_url": "string",
- "owner_name": "string",
- "lat": 0,
- "long": 0,
- "market_id": 0,
- "currency": "string",
- "bedrooms": 0,
- "bathrooms": 0,
- "beds": 0,
- "sleeps": 0,
- "guests_included": 0,
- "room_type": "string",
- "property_type": "string",
- "amenities": [
- "string"
], - "cleaning_fee": 0,
- "star_rating": 0,
- "review_count": 0,
- "adr_365_0": 0,
- "asking_rate_365_0": 0,
- "occupancy_365_0": 0,
- "occupancy_adjusted_365_0": 0,
- "nights_percent_open_365_0": 0,
- "nights_percent_open_90_0": 0,
- "nights_available_365_0": 0,
- "nights_blocked_365_0": 0,
- "nights_bookable_365_0": 0,
- "nights_booked_365_0": 0,
- "lead_time_365_0": 0,
- "length_of_stay_365_0": 0,
- "revenue_365_0": 0,
- "revpar_365_0": 0,
- "revpar_adjusted_365_0": 0,
- "distance_meters": 0,
- "listing_created_at": "2019-08-24T14:15:22Z",
- "listing_last_updated": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "status": "active"
}
]
}Returns the user's own listings that are associated with the set for comparison. Listings are returned in the standard RM API listing format; the id field is the channel listing ID used by the PUT and DELETE endpoints. For shared sets, associated listings the authenticated user does not have access to are omitted. Works for both free and paid sets: associating a listing is set configuration, not KPI data.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
[- {
- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}
]Associates the given listings (the authenticated user's own listings, identified by their channel listing IDs) with the set for comparison. Listings that are already associated are left unchanged. Requires editor or manager access to the set when the set is shared. Works for both free and paid sets: associating a listing is set configuration, not KPI data.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| listing_ids required | Array of strings <= 500 items Channel listing IDs of the user's listings to associate, or their Wheelhouse listing IDs when |
| channel | string Channel name the listings are on, or the literal |
{- "listing_ids": [
- "string"
], - "channel": "string"
}[- {
- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}
]Removes the association between the given listings (identified by their channel listing IDs) and the set. Requires editor or manager access to the set when the set is shared. Works for both free and paid sets: associating a listing is set configuration, not KPI data.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| listing_ids required | Array of strings <= 500 items Channel listing IDs of the user's listings to disassociate, or their Wheelhouse listing IDs when |
| channel | string Channel name the listings are on, or the literal |
[- {
- "id": "string",
- "channel": "string",
- "wheelhouse_id": 0,
- "title": "string",
- "nickname": "string",
- "description": "string",
- "location": {
- "country": "string",
- "postal_code": "string",
- "address": "string",
- "latitude": 0,
- "longitude": 0
}, - "num_bedrooms": 0,
- "num_beds": 0,
- "num_bathrooms": 0,
- "room_type": "string",
- "property_type": "string",
- "currency": "string",
- "star_rating": 0,
- "num_reviews": 0,
- "num_photos": 0,
- "thumb_url": "string",
- "access_level": "owner",
- "amenities": [
- "string"
], - "owner_name": "string",
- "owner_user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string"
}, - "source_user_id": "string",
- "channel_ids": {
- "airbnb": "string",
- "tripadvisor": "string",
- "vrbo": "string",
- "wheelhouse": "string"
}, - "links": {
- "calendar": "string",
- "upgrade": "string"
}, - "security_deposit": 0,
- "base_min_night_stay": 0,
- "listing_preferences": { },
- "market_id": 0,
- "is_active": true,
- "wheelhouse_created_at": "string",
- "number_of_active_units": 0,
- "supported_settings": {
- "checkin_checkout": true,
- "min_stays": true,
- "long_term_discounts": true,
- "long_term_discount_type": "disabled"
}
}
]Returns a night-by-night calendar for each active member listing of the set — the API equivalent of the set calendar in the Wheelhouse app. Each listing carries its own array of nights, with prices converted to a single currency so they are comparable across comps priced differently.
Available only for small sets: a set with more than 25 member listings responds with 422. Every membership counts toward that limit, whatever its status, even though the response itself covers only the active ones. Paid sets only — a free set responds with 404; upgrade it first with POST /sets/{set_id}/upgrade. Both limits follow the detailed per-night scraping that backs this data, which Wheelhouse requests only for paid sets at or under that size.
The shape follows GET /listings/{listing_id}/price_calendar with two deliberate differences, because a comparison listing is not one of your own: there is no is_booked flag and no reservation_id. See booking_probability_percent on the night object for what replaces them.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| start_date | string <date> First stay date to return (inclusive). Defaults to today. |
| end_date | string <date> Last stay date to return (inclusive). Defaults to 545 days out, the maximum calendar horizon. The range may not exceed 3 years. |
| currency | string ISO-4217 3-letter currency code to convert prices to. Defaults to the set's own currency, so nights are comparable across comps priced in different currencies. |
[- {
- "listing_id": 0,
- "title": "string",
- "currency": "string",
- "price_calendar": [
- {
- "stay_date": "2019-08-24",
- "price": 0,
- "currency": "string",
- "is_available": true,
- "booking_probability_percent": 90,
- "block_time": "2019-08-24T14:15:22Z",
- "unit_number": 0
}
]
}
]Returns the history of changes made to the set (membership changes, edits), ordered oldest first and optionally restricted to a date range. Paid sets only. Returns 404 Not Found for a free set — upgrade it first with POST /sets/{set_id}/upgrade.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| after | string <date> Only include changes on or after this date (YYYY-MM-DD). |
| before | string <date> Only include changes before this date (YYYY-MM-DD, exclusive). |
[- {
- "action": "string",
- "edit_details": { },
- "listing_id": 0,
- "created_at": "2019-08-24T14:15:22Z"
}
]Returns daily time-series data for one or more metrics over a date range, aggregated across the active member listings of the set.
Paid sets only. Returns 404 Not Found for a free set — upgrade it first with POST /sets/{set_id}/upgrade.
Available metrics: asking_rate_w_fees, occupancy, occupancy_adjusted, adr_w_fees, lead_time, revpar_adjusted_w_fees, revpar_w_fees, revenue_w_fees, nights_bookable.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| metric | Array of strings Items Enum: "occupancy" "occupancy_adjusted" "nights_bookable" "asking_rate_w_fees" "adr_w_fees" "lead_time" "revpar_adjusted_w_fees" "revpar_w_fees" "revenue_w_fees" Metrics to include. Defaults to all metrics. Send as |
| start_date | string <date> Start of the date range (YYYY-MM-DD). Defaults to today. Must be within 3 years in the past and 1 year in the future. |
| end_date | string <date> End of the date range (YYYY-MM-DD). Defaults to 1 year from today. Must be after |
{- "currency": "string",
- "updated_at": "2019-08-24T14:15:22Z",
- "data": [
- {
- "stay_date": "2019-08-24",
- "occupancy": 0,
- "occupancy_adjusted": 0,
- "nights_bookable": 0,
- "asking_rate_w_fees": 0,
- "adr_w_fees": 0,
- "lead_time": 0,
- "revpar_adjusted_w_fees": 0,
- "revpar_w_fees": 0,
- "revenue_w_fees": 0
}
]
}Returns histogram distributions for one or more metrics for a given calendar month, aggregated across the active member listings of the set.
Paid sets only. Returns 404 Not Found for a free set — upgrade it first with POST /sets/{set_id}/upgrade.
Available metrics: occupancy, occupancy_adjusted, asking_rate_w_fees, adr_w_fees, lead_time, revpar_adjusted_w_fees, revpar_w_fees, length_of_stay.
| set_id required | integer The Wheelhouse internal dynamic set ID. |
| metric | Array of strings Items Enum: "occupancy" "occupancy_adjusted" "asking_rate_w_fees" "adr_w_fees" "lead_time" "revpar_adjusted_w_fees" "revpar_w_fees" "length_of_stay" Metrics to include. Defaults to all metrics. Send as |
| month | string <date> The month to retrieve distributions for (any date within the month, YYYY-MM-DD). Defaults to the start of the current month. |
{- "currency": "string",
- "month": "2019-08-24",
- "updated_at": "2019-08-24T14:15:22Z",
- "data": {
- "property1": [
- {
- "bucket_min_incl": 0,
- "bucket_max_excl": 0,
- "probability": 0,
- "percentile": 0
}
], - "property2": [
- {
- "bucket_min_incl": 0,
- "bucket_max_excl": 0,
- "probability": 0,
- "percentile": 0
}
]
}
}In-app notifications surfaced in the Wheelhouse dashboard at /u/account/notifications. Use these endpoints to list a user's active notifications and to dismiss them. Only non-dismissed, non-expired notifications are returned.
Use the notification settings endpoints to configure which alerts the user receives, and on which channel (in-app or email).
Returns all active (non-dismissed, non-expired) notifications for the authenticated user, ordered most-recent first. These are the same notifications displayed in the Wheelhouse dashboard at /u/account/notifications.
review_url is a relative Wheelhouse dashboard URL that links to the relevant feature page for each notification (e.g. the market report, listing calendar, or dynamic set it relates to).
[- {
- "id": 0,
- "title": "string",
- "body_text": "string",
- "category": "string",
- "reference_type": "string",
- "reference_id": 0,
- "expires_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "review_url": "string"
}
]Marks one or more notifications as dismissed. Dismissed notifications are no longer returned by GET /notifications.
| ids required | Array of integers IDs of notifications to dismiss. |
{- "ids": [
- 0
]
}{- "error": "API token is at rate limit"
}Returns the alert delivery settings for the authenticated user — the event/channel pairs the user currently receives. These control which alerts trigger the notifications returned by GET /notifications (and their email equivalents).
[- {
- "event": "price_posting_error",
- "channel": "inapp"
}
]Enables or disables which alerts the authenticated user receives. Only the settings included in the request are affected — a setting is created when enabled is true and removed when enabled is false. Any event/channel pair not included is left unchanged. Enabling an already-enabled setting (or disabling one that is already off) is a no-op. Returns the user's full set of active settings after the update.
required | Array of objects Alert settings to update. |
{- "settings": [
- {
- "event": "price_posting_error",
- "channel": "inapp",
- "enabled": true
}
]
}[- {
- "event": "price_posting_error",
- "channel": "inapp"
}
]Teams let a Wheelhouse account (the team owner) grant other Wheelhouse accounts access to manage its listings.
Use GET /teams/members to list the team members the authenticated user manages, POST /teams/members/invite to invite a new member by email, DELETE /teams/members/{sub_user_id} to remove one, and the auto_managed_listing_level, assigned_segments, and refresh_auto_managed_listings endpoints to control which of the owner's listings a member can access and at what level.
Use GET /teams/memberships to list the teams the authenticated user belongs to as a member, POST /teams/memberships/{master_user_id} to accept a pending invitation, and DELETE /teams/memberships/{master_user_id} to leave a team or decline an invitation.
Returns the team members managed by the authenticated user.
| include_managed_subs | boolean Default: false Also include the team members of any other Wheelhouse account for which the authenticated user has been granted manager-level (co-host) access to at least one listing — i.e., accounts the authenticated user administers on the owner's behalf. |
[- {
- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]Invites a user by email to join the authenticated user's team. If the invitee does not yet have a Wheelhouse account, a pending one is created for them.
| email required | string Email address of the invitee. |
| billing_delegated | boolean Delegate billing for the invitee to the authenticated user. |
{- "email": "string",
- "billing_delegated": true
}{- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Deactivates a team member, revoking their access to the authenticated user's listings.
| sub_user_id required | integer The Wheelhouse internal user ID of the team member (the |
{- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Sets the access level a team member is automatically granted on the authenticated user's listings. When no portfolio segments are assigned to the team member (see POST /teams/members/{sub_user_id}/assigned_segments), this level applies to all of the authenticated user's listings.
| sub_user_id required | integer The Wheelhouse internal user ID of the team member. |
| level required | string Enum: "N" "R" "E" "F" "M" The auto managed listing level. |
{- "level": "N"
}{- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Sets the portfolio segments a team member auto manages listings for, then immediately refreshes their auto managed listing access to match. Replaces any previously assigned segments.
| sub_user_id required | integer The Wheelhouse internal user ID of the team member. |
| ids required | Array of integers Portfolio segment IDs. |
{- "ids": [
- 0
]
}{- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Re-evaluates and applies the auto managed listing level and assigned segments for a team member against the authenticated user's current listings.
| sub_user_id required | integer The Wheelhouse internal user ID of the team member. |
{- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns the teams the authenticated user belongs to as a team member (i.e. teams owned by another Wheelhouse account).
[- {
- "user_id": 0,
- "sub_user_id": 0,
- "status": "A",
- "user_first_name": "string",
- "user_last_name": "string",
- "user_email": "string",
- "subuser_first_name": "string",
- "subuser_last_name": "string",
- "subuser_email": "string",
- "billing_delegated": true,
- "billing_delegated_at": "2019-08-24T14:15:22Z",
- "auto_managed_listing_level": "N",
- "sub_user_assignments": [
- {
- "id": 0,
- "sub_user_id": 0,
- "assignable_id": 0,
- "assignable_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]Accepts a pending invitation to join another Wheelhouse account's team. Does nothing (still returns success) if there is no matching pending invitation.
| master_user_id required | integer The Wheelhouse internal user ID of the team owner (the |
{- "error": "API token is at rate limit"
}Deactivates the authenticated user's membership in another Wheelhouse account's team. Also used to decline a pending invitation.
| master_user_id required | integer The Wheelhouse internal user ID of the team owner. |
{- "error": "API token is at rate limit"
}Webhooks notify your integration when data changes, so you can keep a local copy fresh without polling. Register an HTTPS endpoint with POST /webhooks, choosing which of the event types listed by GET /webhook_events it should receive.
Events describe what changed, not the new values. A delivery names the listings affected and expects you to re-read the detail through the relevant endpoint — price recommendations, reservations or flags. This keeps payloads small and stable, and means you never have to reconcile a webhook body against an API response.
Deliveries are batched. Events occurring within a five-minute window collapse into a single request whose data.listing_ids names every listing involved, so a nightly repricing run across a large portfolio arrives as a handful of requests rather than thousands. Each delivery only ever names listings you have access to.
Verify every delivery. Requests carry a Wh-Signature header of the form t=<unix timestamp>,v1=<hex>, where the hex is HMAC-SHA256(secret, "<t>.<raw request body>"). Recompute it with the subscription's secret and compare; reject the request if it does not match, or if t is older than your tolerance (five minutes is a reasonable choice) to prevent replay. The secret is returned only when the subscription is created and by POST /webhooks/{id}/rotate_secret — it cannot be read back afterwards.
Delivery is at-least-once, so de-duplicate. Retries reuse the same Wh-Event-Id header (also data-adjacent as the envelope id); treat a repeated id as already handled. Respond with any 2xx status as soon as you have durably accepted the request — do not do your processing before responding, since we time out after 15 seconds. Failed attempts are retried with backoff over roughly 20 minutes, and a subscription that keeps failing is disabled automatically; re-enable it with PUT /webhooks/{id} once your endpoint is healthy. Use GET /webhooks/{id}/deliveries to see what we actually sent and what your endpoint returned.
Returns every event type a webhook subscription can ask for, with the object its ids refer to and how long events of that type are batched before being sent. Use the event_type values in event_types when creating or updating a subscription.
[- {
- "event_type": "recommendations.updated",
- "subject": "listing",
- "batch_window_seconds": 300
}
]Returns the webhook subscriptions belonging to the authenticated user, most recently created first. Signing secrets are not included — they are only available when a subscription is created or its secret is rotated.
[- {
- "id": 0,
- "description": "string",
- "event_types": [
- "string"
], - "enabled": true,
- "consecutive_failures": 0,
- "disabled_at": "2019-08-24T14:15:22Z",
- "last_delivered_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z"
}
]Registers an HTTPS endpoint to receive the given event types. The subscription covers the authenticated user's entire portfolio — owned listings plus listings shared with them to manage — and each delivery names only listings they can access.
The response is the only place the signing secret appears; store it, because it cannot be read back afterwards. If you lose it, use POST /webhooks/{id}/rotate_secret.
The endpoint must be https. Deliveries begin with the next batch window.
| url required | string HTTPS endpoint that deliveries are posted to. |
| event_types required | Array of strings Items Enum: "recommendations.updated" "reservations.ingested" "flags.detected" Event types this subscription should receive. See |
| description | string Label for this subscription. |
{- "event_types": [
- "recommendations.updated"
], - "description": "string"
}{- "id": 0,
- "description": "string",
- "event_types": [
- "string"
], - "enabled": true,
- "consecutive_failures": 0,
- "disabled_at": "2019-08-24T14:15:22Z",
- "last_delivered_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "secret": "whsec_0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a69788796a5b4c3d2e1f0"
}Returns one of the authenticated user's webhook subscriptions, without its signing secret. Responds 404 for a subscription belonging to another account.
| id required | integer The Wheelhouse internal subscription ID. |
{- "id": 0,
- "description": "string",
- "event_types": [
- "string"
], - "enabled": true,
- "consecutive_failures": 0,
- "disabled_at": "2019-08-24T14:15:22Z",
- "last_delivered_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z"
}Updates the fields provided and leaves the rest unchanged. Passing event_types replaces the subscribed set rather than adding to it; omitting it leaves the current set alone.
Set enabled to false to pause delivery, and true to resume it. Resuming also clears the accumulated failure count, so a subscription disabled automatically after sustained failures starts fresh once the endpoint is healthy again.
| id required | integer The Wheelhouse internal subscription ID. |
| url | string HTTPS endpoint that deliveries are posted to. |
| event_types | Array of strings Items Enum: "recommendations.updated" "reservations.ingested" "flags.detected" Replaces the event types this subscription receives. |
| description | string Label for this subscription. |
| enabled | boolean Set |
{- "url": "string",
- "event_types": [
- "recommendations.updated"
], - "description": "string",
- "enabled": true
}{- "id": 0,
- "description": "string",
- "event_types": [
- "string"
], - "enabled": true,
- "consecutive_failures": 0,
- "disabled_at": "2019-08-24T14:15:22Z",
- "last_delivered_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z"
}Removes the subscription and stops all delivery to it. Its delivery history is removed with it.
| id required | integer The Wheelhouse internal subscription ID. |
{- "error": "API token is at rate limit"
}Issues a new signing secret and returns it. Use this if the current secret has leaked or been lost.
The old secret stops being valid immediately, so deliveries signed with the new secret will fail verification until your endpoint is using it. Deploy the new secret promptly after rotating.
| id required | integer The Wheelhouse internal subscription ID. |
{- "id": 0,
- "description": "string",
- "event_types": [
- "string"
], - "enabled": true,
- "consecutive_failures": 0,
- "disabled_at": "2019-08-24T14:15:22Z",
- "last_delivered_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "secret": "whsec_0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c4b5a69788796a5b4c3d2e1f0"
}Returns recent deliveries for the subscription, most recent first, with the HTTP status the endpoint returned and the reason for any failure. Use it to confirm what was sent and to diagnose an endpoint that is failing verification or timing out.
Deliveries are retained for 7 days.
| id required | integer The Wheelhouse internal subscription ID. |
| limit | integer [ 1 .. 200 ] Default: 50 Maximum number of deliveries to return. |
[- {
- "id": 0,
- "event_id": "a7a26ff2-e851-45b6-9634-d595f45458b7",
- "event_type": "string",
- "status": "pending",
- "attempts": 0,
- "response_code": 0,
- "error_message": "string",
- "delivered_at": "2019-08-24T14:15:22Z",
- "failed_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z"
}
]Tells you how your own integration is behaving, without going to the Wheelhouse app to read the audit log by hand.
GET /usage reports volumes, error rates and response times over a window of up to 7 days, broken down by day, by endpoint and by API key. It is cached for a few minutes, so poll it on the order of minutes, not seconds, and read generated_at to see how fresh a response is.
Returns request volumes, error rates and response times over a recent window, broken down by day, by endpoint and by API key. It answers the questions the audit log in the Wheelhouse app answers, without having to read it request by request: which endpoint dominates your traffic, whether a key is being throttled, when errors started.
Covers every RM API key on the account, not just the one making the request. Pass token_id to narrow it to a single key.
The window is limited to 7 days. Pass days_back for a rolling window ending now, or start_time and end_time for an explicit one — a window longer than 7 days returns 400. A window with more requests than can be read in one call sets window.truncated to true and reports the shorter window actually measured, with the most recent requests always covered.
Results are cached for a few minutes. generated_at reports when the figures were computed, which is not the same as when they were served: repeat calls inside the cache window return the same numbers. Polling faster than that gains nothing. If what you want is your live rate limit headroom, read the X-RateLimit-* headers on any response instead — they are current as of that request and cost nothing extra.
Requests are grouped by the endpoint that served them rather than by the exact path called, so every GET /listings/{listing_id}/notes counts towards one entry no matter which listing it named.
| days_back | integer [ 1 .. 7 ] Default: 7 Size in days of a rolling window ending now. Ignored when |
| start_time | string <date-time> Start of an explicit window (ISO-8601). Overrides |
| end_time | string <date-time> End of an explicit window (ISO-8601). Defaults to now. |
| token_id | integer Restrict the figures to a single RM API key. Must be a key belonging to the authenticated user; the |
{- "generated_at": "2019-08-24T14:15:22Z",
- "window": {
- "start": "2019-08-24T14:15:22Z",
- "end": "2019-08-24T14:15:22Z",
- "truncated": true
}, - "totals": {
- "requests": 0,
- "by_status_class": {
- "property1": 0,
- "property2": 0
}, - "rate_limited": 0,
- "avg_response_ms": 0,
- "p95_response_ms": 0
}, - "by_day": [
- {
- "date": "2019-08-24",
- "requests": 0,
- "errors": 0
}
], - "by_endpoint": [
- {
- "method": "GET",
- "path": "/listings/{listing_id}/notes",
- "requests": 0,
- "errors": 0,
- "avg_response_ms": 0
}
], - "by_token": [
- {
- "id": 0,
- "name": "string",
- "last_chars": "string",
- "requests": 0
}
]
}GET /listings/{listing_id}/kpis/monthly, /kpis/quarterly, and /kpis/yearly with nights_percent_open (Nights (Bookable %): bookable nights / calendar nights).GET /sets now takes name and kind filters, so an account with many sets can find one without paging through the whole list. name is a case-insensitive pattern in which * stands for any run of characters — *Palm Springs* matches the phrase anywhere in the name, and a value without a * has to match the name in full. kind takes one value or several comma-separated, and kind=other also matches sets that carry no kind, which is what those sets already report. Sending both filters returns the sets matching each of them, and either combines with the existing pagination parameters.GET /preferences/{listing_id}/changelog was titled as the changelog for a listing's preferences, which undersold it — it has always returned every change recorded against the listing, including prices posted, failed posts and calendar syncs, custom rates added, split or removed, a change of pricing engine, and reservations imported. The title now says so, the description lists what is covered, and GET /listings/{listing_id}/custom_rates now points here for custom rate history rather than leaving it to be inferred that it carries none. No behavior or response-shape change.warnings, naming each setting that was not applied, why (not_supported_by_channel, or partially_supported_by_channel when only part of it was too narrow for the channel), and the attributes it covered. The array is present and empty when everything applied, so it can be read unconditionally. Applies to PUT /preferences, PUT /preferences/{listing_id}, PUT /preferences/{listing_id}/copy and POST /preferences/{listing_id}/preview.supported_settings — whether checkin_checkout, minimum stays and long-term discounts can be set, and which form of long-term discount the channel takes. Check it before sending a setting rather than after. It reflects per-account early access, so two listings on the same channel can differ. See the Listing Preferences section.X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a 429 additionally carries Retry-After. Your current standing arrives with work you were already doing, so pacing an integration no longer costs a request — and the 429 itself now tells you when to retry. See Rate Limits.GET /usage, so an integration can inspect its own API usage rather than reading the audit log in the Wheelhouse app. It reports request volumes, error rates (including 429s) and response times across every RM API key on the account, broken down by day, by endpoint and by key, over a window of up to 7 days. Endpoint breakdowns are grouped by route pattern rather than exact path, so all calls to GET /listings/{listing_id}/notes count as one entry. Results are cached for a few minutes — see generated_at — and a window too busy to read in full is reported as window.truncated with the shorter window it actually covers.GET /listings/{listing_id}/kpis/monthly, /kpis/quarterly, and /kpis/yearly with additional metrics already persisted on the periodic stats tables: adr_fees, asking_rate, nights_available, nights_blocked, nights_bookable, nights_booked, revenue_available, revenue_blocked, revenue_fees, and revenue_fees_taxes. Names match the rolling KPI lexicon.GET /sets/{set_id}/price_calendar, the API equivalent of the set calendar in the app. booking_probability_percent is bounded to 10–90 for unavailable nights, mirroring the app, which renders those extremes as <10% and >90% rather than asserting certainty about a listing it only scrapes; an available night reports 0. The rest: a night-by-night calendar for each active member listing of a set, with prices converted to one currency so comps priced differently are comparable. Paid sets only, and only for sets with at most 25 member listings; a larger set responds with 422. Both limits track where the data comes from: Wheelhouse requests the detailed per-night scraping that backs this endpoint only for paid sets at or under that size, so beyond it there would be little to return. The night object follows GET /listings/{listing_id}/price_calendar except that it carries no is_booked flag and no reservation_id, neither of which applies to a listing that is not yours. In their place, booking_probability_percent reports Wheelhouse's assessment that a night is booked rather than merely held, as a whole percentage.PUT and DELETE /sets/{set_id}/listings, which add and remove a set's member listings — the comparison listings the set is built from. Previously members could only be chosen when the set was created with POST /sets, with no way to adjust them afterwards, so a set could not be refined once built. Identify listings by the internal listing_id values from GET /sets/candidates; only eligible comparison candidates can be added, the same restriction POST /sets applies. Both return the set's members grouped by status, matching GET /sets/{set_id}/listings, and both work on free and paid sets. Not to be confused with the associated_listings endpoints, which manage which of your own listings the set is compared against.GET /sets/{set_id}/listings and GET, PUT, DELETE /sets/{set_id}/associated_listings returned 404 Not Found ("Dynamic set not found") for a free set. Building a set was therefore impossible before paying for it: you could not review which listings were in it, nor associate it with one of your own listings. All four now work on free and paid sets alike. The per-listing metrics returned by /listings were already available ungated through GET /sets/candidates, which returns the same object. The paid gate stays on the set-level analytics — aggregated_metrics, time_series, distribution and changelog.canceled_at to the reservation object returned by GET /listings/{listing_id}/reservations. It carries the timestamp a reservation was cancelled, or null if it stands, and is set whenever status is Canceled — previously the status told you a reservation had been cancelled but not when. Note the single-l spelling, which matches the Canceled status value rather than the cancelled field of the PUT request body.GET /segments/{segment_id}/listings and GET /segments/{segment_id}/aggregated_metrics evaluated a segment's filter only against listings the user owns, so a user whose portfolio is entirely made up of listings shared with them to manage got an empty result from every segment. Both endpoints now match owned and managed listings, consistent with GET /listings, and both accept include_managed_listings to control it (default true for RM API keys, false for channel integration keys).channel=wheelhouse and listing_id is read as a Wheelhouse ID (the wheelhouse_id field of GET /listings, also returned as listing_id by GET /listings/kpis) rather than as a channel listing ID. Wheelhouse IDs are unique across channels, so no channel needs naming alongside them. This works everywhere a listing is identified, including the batched listing_ids parameters and copy_preferences_from. Under channel=wheelhouse a listing you cannot access returns 404, not 403, so the sequential ID space cannot be walked to discover other accounts' listings; the channel-listing-ID form keeps its existing 403. See Identifying Listings. Existing calls are unaffected — omitting channel=wheelhouse keeps the channel listing ID behavior.GET /webhook_events, GET /webhooks, POST /webhooks, GET /webhooks/{id}, PUT /webhooks/{id}, DELETE /webhooks/{id}, POST /webhooks/{id}/rotate_secret, and GET /webhooks/{id}/deliveries. Register an HTTPS endpoint to be notified when price recommendations change (recommendations.updated), when new reservations are ingested (reservations.ingested), or when new listing flags are detected (flags.detected), instead of polling for changes. Deliveries are batched over a five-minute window, name the affected listing_ids rather than carrying the changed values, and are signed with a per-subscription HMAC-SHA256 Wh-Signature header. See the Webhooks section for verification and retry semantics.GET /listings/kpis, which returns one rolling-window KPI for every listing the authenticated user can access, ranked by value and paginated. It answers portfolio-wide questions — best and worst performers on a metric — in one call rather than one per listing. Choose the metric and window with metric and window; pass currency to convert monetary metrics before ranking so that portfolios spanning currencies order correctly. Each row carries listing_id (Wheelhouse's id), partner_listing_id (the channel's), value, currency, and updated_at. Comp-set metrics are not covered yet.GET /listings/{listing_id}/kpis/monthly, /kpis/quarterly, and /kpis/yearly were described as returning only history. They have always returned future periods as well — monthly spans up to 15 months back and up to 12 months forward, quarterly and yearly likewise extend up to 12 months ahead. The word "historical" has been dropped from their titles and each endpoint now documents its full window, with a note that current and future periods reflect bookings on the books plus asking rates for open nights and will therefore change as bookings come in. No behavior or response-shape change.include_managed_listings on GET /listings now defaults to true. GET /listings returns every listing the authenticated user can access — owned listings plus listings shared with them to manage — where it previously returned owned listings only unless the parameter was passed explicitly. Pass include_managed_listings=false to keep the previous behavior. Use each listing's access_level and owner_user to tell the two apart.owner_user to the listing response. It identifies the Wheelhouse account a listing belongs to (id, email, first_name, last_name), which makes it possible to tell whose portfolio each listing sits in when a response mixes owned and managed listings — for example GET /listings?include_managed_listings=true. Note that neither owner_name (the property owner name supplied by the channel) nor source_user_id (the host ID in the channel's own namespace) identifies a Wheelhouse account; their descriptions have been clarified accordingly.GET /listings/{listing_id}/kpis to cover the full Wheelhouse metrics lexicon, now served from a dedicated rolling-stats store. New metrics: adr_fees, asking_rate_fees, nights_bookable, nights_booked, nights_calendar, nights_percent_open, pickup_bookings, revenue_fees, revenue_fees_taxes, last_booked_days, lead_time, length_of_stay. nights_available, nights_blocked, revenue_available, revenue_blocked, and min_price_occurrence now also return backward-looking (N_0) periods; asking_rate_lowest and asking_rate_highest now return all periods in both directions; pickup now covers all backward-looking periods (7/14/21/30/60/90/180/365). Breaking: revenue_score is now keyed by cumulative forward-looking periods (0_7 … 0_365) instead of the non-overlapping 0_30/31_60/61_90 windows; the scalar last_booked_at field has been removed in favor of the last_booked_days metric; and each metric field is null until rolling stats have been generated for the listing.GET /sets/candidates and GET /sets/{set_id}/listings to the public Wheelhouse metrics lexicon, matching the other RM API KPI endpoints: anr → adr, apr → asking_rate, nrevenue → revenue, nrevpar → revpar, nrevpar_open → revpar_adjusted, open_occupancy → occupancy_adjusted, openness → nights_percent_open, los → length_of_stay, and *_nights → nights_* (each keeps its _365_0/_90_0 period suffix).GET /sets/candidates (search market listings with metrics near a location to build a set from), POST /sets (create a free set from selected listings), and POST /sets/{set_id}/upgrade (purchase the paid Dynamic Sets plan for a set to unlock its KPI endpoints). GET /sets and GET /sets/{set_id} now also return free sets, each carrying an is_paid flag.GET /segments/{segment_id}/aggregated_metrics endpoint. Returns monthly performance metrics aggregated across the listings matched by a segment's filter, mirroring GET /sets/{set_id}/aggregated_metrics. Monetary values default to the currency of the segment's most common market.GET /notification_settings and PUT /notification_settings endpoints. Users can now read which alerts they receive and enable or disable individual alert event/channel (in-app or email) settings via the API.GET /teams/members, POST /teams/members/invite, DELETE /teams/members/{sub_user_id}, POST /teams/members/{sub_user_id}/auto_managed_listing_level, POST /teams/members/{sub_user_id}/assigned_segments, POST /teams/members/{sub_user_id}/refresh_auto_managed_listings, GET /teams/memberships, POST /teams/memberships/{master_user_id}, and DELETE /teams/memberships/{master_user_id} to manage team members and memberships.POST /segments endpoint. Creates a new portfolio segment owned by the authenticated user. Accepts filter_backend to define the listing filter criteria.PUT /segments/{segment_id} endpoint. Updates the name, description, filter_backend, and/or default status of an existing segment.POST /listings/{listing_id}/sync endpoint. Triggers a manual sync that pushes the latest Wheelhouse price recommendations to the connected channel and refreshes reservation data — equivalent to the Sync button in the UI. Available on paid plans only; subject to a per-day rate limit and a 60-second debounce.GET /listings/{listing_id}/base_price_history endpoint. Returns a daily log of Wheelhouse base price recommendations and effective base prices for a listing over the last 30 days (or a custom date range).GET /listings/{listing_id}/calendar_day_history endpoint. Returns the history of price postings and calendar state snapshots for a specific stay date. Requires the Historical Price Changes feature on the listing's plan.GET /listings/{listing_id}/kpis with additional metrics: revenue_available, revenue_blocked, min_price_occurrence, occupancy_neighborhood, occupancy_neighborhood_pp, occupancy_neighborhood_ratio, occupancy_neighborhood_adjusted, occupancy_neighborhood_adjusted_pp, occupancy_neighborhood_adjusted_ratio (all forward-only, periods 7/14/21/30/60/90/180/365); comp_set_occupancy, comp_set_occupancy_adjusted, comp_set_revenue (forward-only, periods 7/30/60); pickup (backward-only, periods 7/14/30); asking_rate_lowest and asking_rate_highest (backward-only, period 365); revenue_score (non-overlapping windows 0–30, 31–60, 61–90 days); and scalar comp_set_count.GET /listings/{listing_id}/custom_rates endpoint. Returns all active and upcoming custom rate periods for a listing, excluding expired ones.GET /listings/{listing_id}/kpis into four dedicated endpoints: GET /listings/{listing_id}/kpis (rolling-window metrics — bidirectional periods 7/14/21/30/60/90/180/365), GET /listings/{listing_id}/kpis/monthly (up to 15 months back incl. default dynamic-set metrics), GET /listings/{listing_id}/kpis/quarterly (up to 5 recent quarters), and GET /listings/{listing_id}/kpis/yearly (up to 5 years). Each response includes currency. The old days parameter is no longer accepted.GET /notifications and POST /notifications/dismiss endpoints. Users can now list their active in-app notifications and dismiss specific ones by ID via the API.expires_at field to PUT /listings/{listing_id}/custom_rates and PUT /listings/{listing_id}/bulk_custom_rates. Custom rates can now be set with an expiry timestamp after which they are no longer applied.GET /listings/{listing_id}/fee_impact_calendar endpoint. Returns a per-date fee multiplier derived from the listing's estimated fee setting. Multiply any nightly price by the multiplier to get the fee-inclusive price.GET /listings/{listing_id}/min_stay_calendar endpoint. Returns the per-date minimum stay derived from the listing's minimum stay rules for a given date range.GET /listings/{listing_id}/notes, POST /listings/{listing_id}/notes, PUT /listings/{listing_id}/notes/{note_id}, and DELETE /listings/{listing_id}/notes/{note_id} to manage the notes of a listing.GET /sets, GET /sets/{set_id}, GET /sets/{set_id}/aggregated_metrics, GET /sets/{set_id}/listings, GET /sets/{set_id}/associated_listings, PUT /sets/{set_id}/associated_listings, DELETE /sets/{set_id}/associated_listings, GET /sets/{set_id}/changelog, GET /sets/{set_id}/time_series, and GET /sets/{set_id}/distribution. RM API users can access their paid dynamic sets.GET /listings/{listing_id}/neighborhood/pricing endpoint to fetch daily neighborhood price data (median, p25, p75, listing count) for the listing's local cluster.GET /listings/{listing_id}/neighborhood/occupancy endpoint to fetch daily neighborhood occupancy and booking model data for the listing's local cluster.GET /listings/{listing_id}/last_posted_prices endpoint. Returns the last price posted to the channel per stay date. For available nights this is the most recently posted price; for booked nights it is the last price posted at or before the time the booking was recorded.GET /market_report, GET /market_report/{market_id}/time_series, and GET /market_report/{market_id}/distribution endpoints. RM API users can access market-level data for markets in which they have listings.GET /listings/{listing_id}/price_calendar endpoint to fetch the price calendar for a single listing.GET /listings/{listing_id}/base_price_recommendation endpoint to include attribution breakdown.GET /listings, GET /listings/{listing_id}, GET /listings/{listing_id}/pricing_tier, GET /listings/{listing_id}/recent_changes, GET /listings/{listing_id}/kpis.GET /listings/{listing_id}/price_recommendations, GET /listings/{listing_id}/base_price_recommendation, GET /listings/{listing_id}/checkin_checkout, GET /listings/{listing_id}/min_max_prices, GET /listings/{listing_id}/monthly_seasonality.GET /preferences, PUT /preferences, GET /preferences/{listing_id}, PUT /preferences/{listing_id}, PUT /preferences/{listing_id}/copy, PUT /preferences/{listing_id}/{setting}, GET /preferences/{listing_id}/long_term_discounts, GET /preferences/{listing_id}/changelog, POST /preferences/{listing_id}/preview.PUT /listings/{listing_id}/custom_rates, DELETE /listings/{listing_id}/custom_rates, PUT /listings/{listing_id}/bulk_custom_rates, DELETE /listings/{listing_id}/bulk_custom_rates.GET /listings/{listing_id}/reservations (with date_filter_type parameter).GET /listings/{listing_id}/tags, PUT /listings/{listing_id}/tags, GET /listings/{listing_id}/flags.GET /segments, GET /segments/{segment_id}/listings.