Dynamic sets are saved collections of relevant properties that meet your specified criteria. They're built inside Wheelhouse Navigator — a map-based interface that combines geographic, performance, pricing, inventory type, operator type, LOS & fees, and amenity data. Use dynamic sets for benchmarking, pricing strategy, owner comms, listing acquisition, and more.
Dynamic sets include two distinct listing types: the member listings inside the set (properties matching your criteria), and your own associated listings that you've linked for side-by-side comparison.
Important
The RM API works with both free and paid dynamic sets. Listing sets, viewing a set, its member listings and its associated listings all work for free sets. The performance endpoints (aggregated metrics, time series, distribution, changelog and the price calendar) are for paid sets only and return 404 Not Found for a free set. To upgrade a free set, use POST /sets/:set_id/upgrade — this charges your payment method.
GET /sets
List all dynamic sets, free and paid, that the authenticated user owns or has shared access to. Use the is_paid field to tell them apart. Results are ordered by most recently updated first.
curl "https://api.usewheelhouse.com/ss_api/v1/sets" \
-H "X-Integration-Api-Key: your_api_key_here"
Query parameters
name(string, optional) — match sets by name.*stands for any run of characters, so*Palm Springs*matches sets with that phrase anywhere in the name; a value with no*has to match the whole name. Matching ignores casekind(string, optional) — match sets by theirkind. Comma-separate several to match any of them, e.g.competitive,market. Sets with no kind are reported asother. An unrecognised value returns400per_page(integer, optional, default:50) — number of sets per page (max 100)page(integer, optional) — page numberoffset(integer, optional) — number of items to skip
Response — array of dynamic set objects:
[
{
"id": 7,
"user_id": 1001,
"name": "Beachfront Comps",
"description": "Top comps near our Malibu property",
"kind": "competitive",
"currency": "USD",
"is_static": true,
"filters": {},
"boundary": [...],
"listing_counts": {
"active": 8,
"hidden": 1,
"review": 0,
"removed": 1
},
"updated_at": "2026-01-15T08:30:00Z"
}
]
Response fields
id— Wheelhouse's internal dynamic set ID (integer)kind— the use-case label for the set. One of:competitive,market,neighborhood,marketing,acquisition,underwriting,merchandising,otheris_paid—trueif the set is on the paid Dynamic Sets plan. Only paid sets expose the performance endpoints; free sets return404thereis_static—trueif member listings are a frozen snapshot;falseif the set auto-syncs based on its boundary and filterslisting_counts— member counts broken down by status:active,hidden,review,removedboundary— geographic boundary of the set
Status codes
200— array of dynamic sets401— API key authorization failed
GET /sets/:set_id
Get detailed information about a single dynamic set, including its definition, boundary, and member counts per status.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Status codes
200— dynamic set object (same shape as list response)401— API key authorization failed404— not found or not accessible
GET /sets/:set_id/aggregated_metrics
Get monthly performance metrics aggregated across active member listings.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/aggregated_metrics?currency=USD&dates[]=2026-05-01&dates[]=2026-06-01" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
currency(string, optional) — ISO 4217 3-letter currency code. Defaults to the set's currency.dates(string[], optional) — restrict to months starting on these dates (YYYY-MM-DD, first of month). Send more than one in brackets (?dates[]=2026-05-01&dates[]=2026-06-01); a key repeated without brackets keeps only its last value. Defaults to all available.
Status codes
200— aggregated metrics per period401— API key authorization failed404— not found, not accessible, or not a paid set
GET /sets/:set_id/listings
List member listings grouped by membership status, with trailing year performance metrics.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/listings" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Response
{ "active": [...], "hidden": [...], "review": [...], "removed": [...] }active— currently active membershidden— hidden from the set viewreview— pending review before being addedremoved— previously removed members
Status codes
200— member listings grouped by status401— API key authorization failed404— not found or not accessible
GET /sets/:set_id/time_series
Get daily time-series metrics aggregated across active member listings over a date range.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/time_series?metric[]=occupancy&metric[]=adr_w_fees&start_date=2026-01-01&end_date=2026-06-30" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
metric(string[], optional) — metrics to include. Available:asking_rate_w_fees,occupancy,occupancy_adjusted,adr_w_fees,lead_time,revpar_adjusted_w_fees,revpar_w_fees,revenue_w_fees,nights_bookable. Defaults to all. Send more than one in brackets (?metric[]=occupancy&metric[]=adr_w_fees); a key repeated without brackets keeps only its last value.start_date(string, optional) — YYYY-MM-DD. Defaults to today. Max 3 years past, 1 year future.end_date(string, optional) — YYYY-MM-DD. Defaults to 1 year from today. Must be afterstart_date.
Status codes
200— time-series data204— not enough data400— invalid parameter value401— API key authorization failed404— not found, not accessible, or not a paid set
GET /sets/:set_id/distribution
Get histogram distributions for one or more metrics for a given calendar month.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/distribution?metric[]=occupancy&metric[]=adr_w_fees&month=2026-06-01" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
metric(string[], optional) — metrics to include. Available:occupancy,occupancy_adjusted,asking_rate_w_fees,adr_w_fees,lead_time,revpar_adjusted_w_fees,revpar_w_fees,length_of_stay. Defaults to all. Send more than one in brackets (?metric[]=occupancy&metric[]=adr_w_fees); a key repeated without brackets keeps only its last value.month(string, optional) — the target month (YYYY-MM-DD or YYYY-MM, e.g.2026-06-01or2026-06). Defaults to start of current month.
Response
Each metric key maps to an array of histogram buckets:
{
"currency": "USD",
"month": "2026-06-01",
"data": {
"occupancy": [
{ "bucket_min_incl": 0.0, "bucket_max_excl": 0.1, "probability": 0.0625, "percentile": 0.0625 }
],
"adr_w_fees": [...],
"lead_time": [...],
"length_of_stay": [...]
}
}
Metric units:
asking_rate_w_fees,adr_w_fees,revpar_adjusted_w_fees,revpar_w_fees— monetary, in thecurrencyat the top leveloccupancy,occupancy_adjusted— decimal fraction (0–1); multiply by 100 for percentagelead_time— days; negative = advance booking (booked before stay date)length_of_stay— nights
Status codes
200— metric distributions for the month204— not enough data400— invalid parameter value401— API key authorization failed404— not found, not accessible, or not a paid set
GET /sets/:set_id/associated_listings
List the authenticated user's own listings associated with the set for comparison. For shared sets, listings you don't have access to are omitted.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/associated_listings" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Status codes
200— array of associated listing objects401— API key authorization failed404— not found or not accessible
PUT /sets/:set_id/associated_listings
Associate your own listings with a dynamic set. Already-associated listings are left unchanged. Requires editor or manager access on shared sets.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/sets/7/associated_listings" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "listing_ids": ["abc123", "def456"], "channel": "airbnb" }'
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Request body
listing_ids(string[], required) — channel listing IDs to associate. Maximum 500.channel(string, conditional) — required if it cannot be derived from the API key.
Status codes
200— updated array of associated listing objects400— invalid parameters401— API key authorization failed403— insufficient access or read-only API key404— set or listing not found, or not accessible409— concurrent request in progress; retry after it completes
DELETE /sets/:set_id/associated_listings
Remove your own listings from a dynamic set. Requires editor or manager access on shared sets.
curl --request DELETE "https://api.usewheelhouse.com/ss_api/v1/sets/7/associated_listings?listing_ids[]=abc123&listing_ids[]=def456&channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
listing_ids(string[], required) — channel listing IDs to remove. Maximum 500. Send more than one in brackets (?listing_ids[]=abc123&listing_ids[]=def456); a key repeated without brackets keeps only its last value.channel(string, conditional) — required if it cannot be derived from the API key.
Status codes
200— updated array of associated listing objects400— invalid parameters401— API key authorization failed403— insufficient access or read-only API key404— set or listing not found, or not accessible409— concurrent request in progress; retry after it completes
GET /sets/:set_id/changelog
Get the history of changes to a dynamic set — membership additions, removals, and edits — ordered oldest first.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/changelog?after=2026-01-01" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
after(string, optional) — only include changes on or after this date (YYYY-MM-DD)before(string, optional) — only include changes before this date (YYYY-MM-DD, exclusive)
Status codes
200— array of changelog entries401— API key authorization failed404— not found, not accessible, or not a paid set
POST /sets
Create a free dynamic set. Add candidate listings (from GET /sets/candidates) by passing their internal listing_id values; they are added with the active status. The set is created on the free plan — upgrade it with POST /sets/:set_id/upgrade to use the performance endpoints.
curl --request POST "https://api.usewheelhouse.com/ss_api/v1/sets" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Beachfront Comps",
"description": "Top comps near our Malibu property",
"listing_ids": [101, 102, 103]
}'
Request body
name(string, required) — name of the dynamic setdescription(string, optional) — description of the setcurrency(string, optional) — ISO-4217 3-letter currency code. Defaults to the currency of the most common market among the set's listingslisting_ids(integer[], optional) — internal listing IDs (thelisting_idvalues fromGET /sets/candidates) to add as members. Maximum 500 per request
Status codes
201— the created dynamic set400— validation error, such as a missing name or more than 500 listing IDs401— API key authorization failed403— the API key is read-only404— one or more of the listing IDs were not found
GET /sets/candidates
Search market listings to choose from when building a dynamic set, with their trailing-year performance metrics. Provide either lat, long and radius (radius in meters) or one or more market_ids. Results are ordered nearest-first, each with a distance_meters value, and are paginated. Pass the returned listing_id values to POST /sets to add them as members. This endpoint isn't tied to a set, so no set plan applies.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/candidates?lat=34.03&long=-118.69&radius=3000&min_bedrooms=2" \
-H "X-Integration-Api-Key: your_api_key_here"
Query parameters
lat,long(number) andradius(integer, meters) — search center and radius. Send all three togethermarket_ids(integer[]) — restrict candidates to these markets. Provide this orlat/long/radius. Send more than one in brackets (?market_ids[]=12&market_ids[]=34); a key repeated without brackets keeps only its last valuemin_bedrooms,max_bedrooms(integer) andmin_bathrooms,max_bathrooms(number)room_types(string[]) — normalized room types. Send more than one in brackets (?room_types[]=apartment&room_types[]=house)min_bookable_nights_0_365(integer) — minimum bookable nights over the next 365 daysmin_open_occupancy_0_365(number, 0–1) — minimum forward-looking adjusted occupancymin_open_occupancy_365_0(number, 0–1) — minimum trailing-year adjusted occupancy. Defaults to0.35min_bookable_nights_365_0(integer) — minimum trailing-year bookable nights. Defaults to127per_page(integer) andpage(integer) — pagination
Status codes
200— array of candidate listings, nearest first400— neither lat/long/radius nor market_ids were provided, or lat/long/radius were not sent together401— API key authorization failed
POST /sets/:set_id/upgrade
This charges your payment method
Upgrading creates a real paid subscription. There is no sandbox or test mode.
Upgrade a free dynamic set to the paid Dynamic Sets plan, so its performance endpoints (aggregated metrics, time series, distribution, changelog and the price calendar) become available. Only the set's owner or a manager-level collaborator can upgrade a set; editors cannot. The billable user must have a valid payment method on file. Returns the upgraded set.
curl --request POST "https://api.usewheelhouse.com/ss_api/v1/sets/7/upgrade" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Status codes
200— the upgraded (now paid) dynamic set401— API key authorization failed402— no valid payment method on file, or the charge failed403— the API key is read-only, or the user is not the set's owner or a manager404— dynamic set not found or not accessible409— the dynamic set is already on a paid plan
POST /sets/:set_id/share
Share a dynamic set with other users by granting them an access level. Only the set's owner or a manager-level collaborator can share a set. Sharing with a user who already has access updates their level. Returns the updated set. Works for free and paid sets.
curl --request POST "https://api.usewheelhouse.com/ss_api/v1/sets/7/share" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"access": { "F": [2001, 2002], "R": [2003] }
}'
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Request body
access(object, required) — user IDs to grant each access level, keyed by level code:
R— viewer, read-onlyE— restricted editorF— editor; can modify the set and its associated listingsM— manager; can also share and upgrade the setN— disabled; revokes access
Status codes
200— the dynamic set with updated sharing settings400— invalid access levels or user IDs401— API key authorization failed403— the API key is read-only, or the user is not the set's owner or a manager404— dynamic set not found or not accessible
PUT /sets/:set_id/listings
Add member listings to a dynamic set — the comparison listings the set is built from. Identify them by the internal listing_id values returned by GET /sets/candidates; only 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. Works for free and paid sets, and needs editor or manager access when the set is shared.
This is an upsert: a listing already in the set keeps its single membership and takes the requested status. If you leave status out, a member that is currently hidden, review or removed moves back to active, so pass the status explicitly when re-sending a list.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/sets/7/listings" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"listing_ids": [101, 102],
"status": "active"
}'
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Request body
listing_ids(integer[], required) — internal listing IDs to add, thelisting_idvalues fromGET /sets/candidates(not channel listing IDs). At most 500 per requeststatus(string, optional, default:active) — one ofactive,hidden,review,removed
Status codes
200— the set's member listings after the change, grouped by status400— more than 500 listing IDs were sent401— API key authorization failed403— the set is shared with you without editor or manager access, or the API key is read-only404— set not found or not accessible, or one or more listing IDs are not eligible as members409— another request is already in progress for this set; retry after it completes
DELETE /sets/:set_id/listings
Remove member listings from a dynamic set. 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. Works for free and paid sets, and needs editor or manager access when the set is shared.
On a filter-based (non-static) set, membership comes from the set's own filters, so removed members may be restored by the next sync — the same as in the Wheelhouse app.
curl --request DELETE "https://api.usewheelhouse.com/ss_api/v1/sets/7/listings" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "listing_ids": [101, 102] }'
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Request body
listing_ids(integer[], required) — internal listing IDs to remove. IDs that are not members are ignored. At most 500 per request
Status codes
200— the set's member listings after the change, grouped by status400— more than 500 listing IDs were sent401— API key authorization failed403— the set is shared with you without editor or manager access, or the API key is read-only404— dynamic set not found or not accessible409— another request is already in progress for this set; retry after it completes
GET /sets/:set_id/price_calendar
Get a night-by-night price calendar for each active member listing of a set — the API equivalent of the set calendar in the Wheelhouse app. Each listing carries its own array of nights, with prices converted to one currency so comps priced differently can be compared.
Only available for small sets: a set with more than 25 member listings returns 422. Every membership counts toward that limit, whatever its status. Paid sets only — a free set returns 404; upgrade it first.
The shape follows GET /listings/:listing_id/price_calendar, with two differences because a comparison listing isn't one of your own: there is no is_booked flag and no reservation_id. See booking_probability_percent on each night for what replaces them.
curl "https://api.usewheelhouse.com/ss_api/v1/sets/7/price_calendar?start_date=2026-11-01&end_date=2026-11-30¤cy=USD" \
-H "X-Integration-Api-Key: your_api_key_here"
Path parameters
set_id(integer, required) — Wheelhouse internal dynamic set ID
Query parameters
start_date(string, optional) — first stay date, YYYY-MM-DD. Defaults to todayend_date(string, optional) — last stay date, YYYY-MM-DD. Defaults to 545 days out, the maximum calendar horizon. The range may not exceed 3 yearscurrency(string, optional) — ISO-4217 3-letter currency code to convert prices to. Defaults to the set's own currency
Status codes
200— one calendar per active member listing400— the date range exceeds 3 years, ends before it starts, or the currency is not supported401— API key authorization failed404— dynamic set not found, not accessible, or not a paid set422— the set has more than 25 member listings
Related
Segments: Portfolio Groups and Filters
Market Reports & Neighborhood Data: Market-level insights
How to organize and filter listings (tags, segments, dynamic sets)