Wheelhouse Revenue Management API

Overview
The Wheelhouse Revenue Management API provides direct access to price recommendations, listing preferences, custom rates, reservations, and portfolio management for Revenue Management integrations.
Beta Status
This API is currently in beta. The interface and response formats may change in future versions.
Authentication
MCP and AI agents
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.
Direct API integrations
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.
Read-only API keys
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.
Pagination
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.
Rate Limits
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.
Identifying Listings
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— theidfield from the listing object.channel— thechannelfield 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— thewheelhouse_idfield from the listing object.channel— the literal stringwheelhouse.
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.
Multi-Unit Listings
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.
Authentication
- API Key: RmApiKey
All RM API requests require an RM API key sent in this header.
Read-only keys are limited to GET, HEAD, OPTIONS, and POST. PUT and DELETE return 403 Forbidden (as do other disallowed methods), as do POST endpoints that create or modify data.
Security Scheme Type: | apiKey |
|---|---|
Header parameter name: | X-Integration-Api-Key |
License