Listing preferences control how Wheelhouse generates price recommendations for each property — base price, seasonality, discounts, min stay rules, and more. These are called "Settings" in the Wheelhouse app. This reference covers every endpoint for reading, updating, previewing, and copying preferences.
GET /preferences/:listing_id
Read preferences for a single listing.
curl "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here"
Parameters
listing_id(string, path, required) — the channel's unique listing identifierchannel(string, query, required) — the channel name for this listing (fromGET /listings)
Key response fields
listing_id— Wheelhouse's internal numeric ID for this listingpartner_listing_id— the channel's listing ID (same as theidinGET /listings)base_price— the manually set base price (if set, overrides Wheelhouse's recommendation)base_price_adjustment— percentage adjustment to the Wheelhouse recommended base price (only present ifbase_priceis not set)weekly_discount/monthly_discount— discount percentage for stays ≥7 / ≥28 nights (0 = no discount). On listings that accept length-of-stay premiums (every listing whosesupported_settings.long_term_discount_typeiscomplex, and some withrules), values are signed:-10is a 10% discount and10a 10% premiumautomatic_rate_posting_enabled— whether Wheelhouse auto-pushes prices to the channellast_minute_discount/seasonality_adjustment/far_future_premium/day_of_week— objects withtypeset toCON(conservative),REC(recommended),AGG(aggressive), orCUS(custom). Forday_of_week,CUStakes your ownrules, whose values are price multipliers (1.1is 10% higher), andCUSwithoutruleshas no effect. Sent withoutrules,CONandAGGstore the matching preset rulesmooth— a boolean onlast_minute_discount,far_future_premiumandseasonality_adjustment, shown as Smooth in the app. It defaults tofalse, which is stepped, and it is only used whentypeisCUS. Whentrue, the adjustment eases gradually from one rule to the next instead of jumping at each rule's edge, andcustomrules still apply exactly. Onseasonality_adjustment, smoothing also ignores thestep,start_valueandend_valueof monthly rulescurrency— currency used for prices on this listingfee_adjustments— the estimated fees guests pay on top of the nightly rate (shown as "Asking Rate (+Est. Fees)" in the app). An object withtotal_fee_percentage(fees as a percentage of the nightly rate,-100or more;15means guests pay about 15% on top) andauto_update(whentrue, the percentage is recalculated weekly from the fees on recent reservations, replacing what was set; defaults tofalse). It isnullwhen nothing is configured, otherwise both keys are present. When you update it, the object replaces the stored one as a whole, so send both keys;nullclears it. It is whatGET /listings/:listing_id/fee_impact_calendarreadshistorical_anchoring_mode— how a historical anchoring percentage (Historical Protections in the app) turns the historical price into a floor for the recommendation:blended(default) oranchor_only.blendedaverages the historical price with the recommendation, using the percentage as the weight on the historical price: at 50%, a $1,200 historical price and a $400 recommendation give $800.anchor_onlytakes the percentage of the historical price alone, so at 50% the floor is $600: a $400 recommendation rises to $600 and a $700 one stays at $700. Either only ever raises a price, and from 100% up both give the same pricehistorical_anchoring_price_source— which historical price anchoring weighs in:observed(default), the listing's price as Wheelhouse saw it on the channel once the date booked;posted, the price Wheelhouse last posted for the date before it booked, so dates Wheelhouse never posted a price for are not anchored; orposted_with_fallback, the posted price where there is one and the observed price otherwisesupported_settings— which settings this listing's channel can act on. A setting reportedfalseis discarded on write rather than posted to the channel, so check it before sending that setting
GET /preferences
Read preferences for multiple listings at once.
curl "https://api.usewheelhouse.com/ss_api/v1/preferences?channel=airbnb&listing_ids[]=12345678&listing_ids[]=87654321" \
-H "X-Integration-Api-Key: your_api_key_here"
Query parameters
channel(string, required) — the channel name for these listingslisting_ids(string[], optional) — listing IDs to include. Send more than one in brackets (?listing_ids[]=12345678&listing_ids[]=87654321); a key repeated without brackets keeps only its last value. If omitted, returns an empty array (not all listings)
Returns an array of preference objects, one per listing.
PUT /preferences/:listing_id
Update preferences for a single listing. Send only the fields you want to change — everything else stays unchanged.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"base_price": 200, "monthly_discount": 10}'
Parameters
listing_id(string, path, required)channel(string, query, required)
Important behavior
Partial updates apply at the top level only. If you send a field that holds an array of rules (e.g. minimum_price_rules_v3), the entire array is replaced — individual rules cannot be patched. Always fetch current preferences first and include every rule you want to keep.
These settings are objects, and the object you send replaces the stored one as a whole:
checkin_checkout— sendactiveand bothcheck_in_rulesandcheck_out_rules. A request missing either array is rejected with400. An emptycheck_out_rulesleaves check-out unrestricted. Rule values are allow flags:1allows the day and0blocks it, and aday_of_weekrule has 7 values, with index 0 = Sunday. Where rules overlap, the more specific rule type wins (a date-specificcustomrule over aday_of_weekrule); between rules of the same type, the later one in the array wins.auto_adjust, whentrue, opens extra check-in and check-out days around unavailable nights so open stretches between bookings can still be booked.occupancy_pacing—{}means pacing is off, which is the default for a new listing; omit it to leave pacing unchanged. A non-empty object needsadjustedandpacing, andpacingmust include a matrix withtypeglobal, otherwise the request is rejected with400. Each column is a lead-time window in days from today, and each row is an occupancy band: a row covers occupancy aboveminup to and includingmax, and the first matching row wins.valuesholds one array per row with one whole percentage per column (-10is a 10% decrease), each-100or more. Any other shape is rejected with400.gap_night— thecustomarray replaces the stored one.
Example, check-in on Friday and Saturday only, check-out any day:
{
"checkin_checkout": {
"active": true,
"auto_adjust": false,
"check_in_rules": [{"type": "day_of_week", "day_of_week_values": [0, 0, 0, 0, 0, 1, 1]}],
"check_out_rules": [{"type": "day_of_week", "day_of_week_values": [1, 1, 1, 1, 1, 1, 1]}]
}
}
Write responses include a warnings array, empty when everything applied. Each entry names the setting and a reason: not_supported_by_channel (the channel has no such feature and everything sent for it was dropped), partially_supported_by_channel (only the excess was dropped), or not_supported_for_multi_unit (the setting is stored but has no effect on price because the listing has more than one unit, which is the case for gap night pricing).
Gap night pricing
The gap_night setting is "Gaps & Adjacencies" in the Pricing Engine panel. It sets the price multiplier for open nights between bookings. It only affects prices, and it is separate from the gap and adjacency rule types in the minimum stay rules, which control minimum stay for those nights.
Set type to CON, REC or AGG for a preset, or to CUS to write your own rules in custom. CUS without custom is rejected; an empty array is allowed. Each custom rule has:
gap(integer, required) — the rule applies to gaps of this many nights or fewerday_of_week(array of integers, required) — the weekdays the rule applies to, 0 = Sunday through 6 = Saturday, each at most onceadjustment(number, required) — a price multiplier, greater than 0 and at most 10.0.8is a 20% discountadjacent(string, optional) — leave it out to match open nights with an unavailable night on both sides ("In between").leftmatches the firstgapopen nights after an unavailable night ("Only after").rightmatches the lastgapopen nights before one ("Only before")
When several rules match a night, rules without adjacent are checked first, then left, then right. Within those, the rule with the smallest gap that still covers the gap wins, and among rules with the same gap the largest adjustment wins.
Example, 20% off on Sunday to Thursday for gaps of 2 nights or fewer:
{
"gap_night": {
"type": "CUS",
"custom": [{"gap": 2, "day_of_week": [0, 1, 2, 3, 4], "adjustment": 0.8}]
}
}
Gap night pricing does not apply to listings with more than one unit. The setting is still accepted, and the response carries a not_supported_for_multi_unit warning.
Status codes
400— a setting in the request has the wrong shape; the message names the field423— preferences not yet initialized for this listing; retry after a brief delay409— another request already in progress for this listing; retry after it completes
PUT /preferences/:listing_id/:setting
Update a single pricing setting to a preset level.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678/seasonality_adjustment?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"type": "AGG"}'
Returns 204 No Content on success.
Supported settings
base_price_adjustment— body:{"type": "CON" | "REC" | "AGG"}day_of_week— body:{"type": "CON" | "REC" | "AGG"}seasonality_adjustment— body:{"type": "CON" | "REC" | "AGG"}last_minute_discount— body:{"type": "CON" | "REC" | "AGG"}far_future_premium— body:{"type": "CON" | "REC" | "AGG"}automatic_rate_posting— body:{"enabled": true | false}
Parameters
listing_id(string, path, required)setting(string, path, required) — one of the settings listed abovechannel(string, query, required)
PUT /preferences (bulk)
Update preferences across multiple listings in one request. This is a bulk update, which a user with restricted editor access to a shared listing may not make: such a listing is reported in the response with status 403, however many listings the request names. Use PUT /preferences/:listing_id for it instead.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/preferences?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"listing_preferences": [
{"listing_id": "12345678", "base_price": 200},
{"listing_id": "87654321", "base_price": 180}
]
}'
Parameters
channel(string, query, required)listing_preferences(array, body, required) — each entry must include:listing_id(string, required) — the channel's listing IDany preference fields to update (same fields as
PUT /preferences/{listing_id})
Status codes
207— some updates succeeded, some failed; check the response body for per-listing breakdown424— all updates failed
PUT /preferences/:listing_id/copy
Copy preferences from one listing to another. This overwrites the target listing's existing preferences.
The :listing_id in the path is the target (the listing being overwritten). The source listing is identified in the request body.
curl --request PUT "https://api.usewheelhouse.com/ss_api/v1/preferences/87654321/copy" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"channel": "airbnb",
"copy_preferences_from": {
"listing_id": "12345678",
"channel": "airbnb"
}
}'
Request body
channel(string, required) — channel name of the target listingcopy_preferences_from(object, required) — identifies the source listing:listing_id(string, required) — the source listing's channel IDchannel(string, optional) — channel name of the source listing
copy_custom_rates(boolean, optional, default:true) — whentrue, also copies custom rates from the source to the target
POST /preferences/:listing_id/preview
Preview how a preference change would affect daily prices — without saving anything. See the How to preview pricing changes before applying them guide for full details and code examples.
curl --request POST "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678/preview?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"base_price": 200}'
Returns the same format as GET /listings/{listing_id}/price_recommendations, with global_min_stay and automatic_rate_posting_enabled omitted. Nothing is saved. A setting with the wrong shape returns 400, and the message names the field.
GET /preferences/:listing_id/long_term_discounts
Get the long-term discount settings for a listing (weekly and monthly discounts).
curl "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678/long_term_discounts?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here"
Response fields
weekly_discount— discount percentage for stays ≥7 nights (integer, nullable)monthly_discount— discount percentage for stays ≥28 nights (integer, nullable)
These are the same values as weekly_discount and monthly_discount in GET /preferences/{listing_id}.
GET /preferences/:listing_id/changelog
Get a log of recent preference changes for a listing — useful for auditing who changed what and when.
curl "https://api.usewheelhouse.com/ss_api/v1/preferences/12345678/changelog?channel=airbnb" \
-H "X-Integration-Api-Key: your_api_key_here"
Query parameters
channel(string, required)start_date(string, optional) — start of the date range (YYYY-MM-DD); defaults to 30 days ago, clamped to 90 days maxend_date(string, optional) — end of the date range (YYYY-MM-DD); defaults to tomorrow
Response
Returns an events array. Each event includes:
time— when the change occurred (ISO 8601)source— who triggered it:"Wheelhouse"(system),"User"/"User <name>","API"/"API <name>","Customer Support","Wheelhouse team"/"Wheelhouse team <name>". Reservation imports show the name of the person who ran them, including past imports; imports from before the name was recorded still show just"Wheelhouse team". Fixed rate changes made through the RM API or admin tools show where the change came from instead of always showing"User"; older entries still show"User". Preference and custom rate copies made through the RM API show as"API <name>"event— type of event:"Prices posted","Calendar synced","Settings changed","Custom rates","Reservations imported"status—"success","warning"(partial success: for example some prices posted, but the channel rejected some dates;msgsays what to fix) or"error"msg— human-readable description of the change
Related
How to read and update pricing preferences
How to preview pricing changes before applying them