AI Pricing
A recommended nightly rate is pre-computed for every one of your listings, every night, out 365 days. You apply or decline. Applied rates fan out to every connected channel — Airbnb, Booking.com, Vrbo, Plum Guide — automatically. Powered by Atlas. Learn more about Atlas →
How it works
- Each listing-night is scored against demand, comp set, occupancy, lead time, day of week, and a market events feed.
- The output is a per-night
recommended_rateplus the factors that drove it. Read it fromGET /v1/listings/{id}/pricing. - You either apply (push to all connected channels) or decline (no-op, recorded for the audit trail) via
POST /v1/listings/{id}/pricing. - Behind the scenes, applying triggers the channel adapters — Airbnb pushes through the Airbnb pricing API, Booking.com through CNS, Vrbo through Expedia rates, Plum Guide through their pricing endpoint.
Recommendations are advisory
Get recommendations
Returns one row per night for a date range, with the recommended rate, the rate currently live on your channels, and the contributing factors so you can show the "why".
/v1/listings/{id}/pricingcurl 'https://api.repull.dev/v1/listings/lst_abc123/pricing?from=2026-06-01&to=2026-06-30' \ -H 'Authorization: Bearer sk_live_...'
Query parameters
fromstring (YYYY-MM-DD)RequiredFirst night in the range. Inclusive.
tostring (YYYY-MM-DD)RequiredLast night in the range. Inclusive. Max 365 nights from `from`.
Response (excerpt)
{
"listing_id": "lst_abc123",
"currency": "EUR",
"data": [
{
"date": "2026-06-12",
"current_rate": 180,
"recommended_rate": 235,
"delta_pct": 0.306,
"applied": false,
"factors": {
"demand": 1.74,
"comp_set": 224,
"occupancy": 0.92,
"lead_time": "11d",
"day_of_week": "Friday",
"events": ["Rock in Rio Lisboa — Day 1"]
}
},
{
"date": "2026-06-13",
"current_rate": 180,
"recommended_rate": 248,
"delta_pct": 0.378,
"applied": false,
"factors": {
"demand": 1.81,
"comp_set": 238,
"occupancy": 0.95,
"lead_time": "12d",
"day_of_week": "Saturday",
"events": ["Rock in Rio Lisboa — Day 2", "Festas de Lisboa"]
}
}
],
"computed_at": "2026-04-30T03:14:09.000Z"
}Apply or decline
Apply pushes the recommended rate to every connected channel for that night. Decline records a no-op so the audit trail and ML feedback loop know you saw the recommendation and chose not to take it.
/v1/listings/{id}/pricingcurl -X POST 'https://api.repull.dev/v1/listings/lst_abc123/pricing' \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{
"decisions": [
{ "date": "2026-06-12", "action": "apply" },
{ "date": "2026-06-13", "action": "apply" },
{ "date": "2026-06-14", "action": "decline", "reason": "owner block" }
]
}'Body
decisions[].datestring (YYYY-MM-DD)RequiredThe night the decision applies to.
decisions[].action"apply" | "decline"Requiredapply pushes the recommended rate to every connected channel. decline is a no-op recorded for audit + ML feedback.
decisions[].ratenumberOptional override. If you pass a rate, that rate is pushed instead of the recommendation. Useful when a human edits the suggestion before applying.
decisions[].reasonstringFree-form note attached to the decline. Stored on the audit trail.
Response (excerpt)
{
"listing_id": "lst_abc123",
"applied": 2,
"declined": 1,
"fanout": {
"airbnb": { "ok": 2, "errors": 0 },
"booking": { "ok": 2, "errors": 0 },
"vrbo": { "ok": 2, "errors": 0 }
},
"audit_id": "pa_8gQrT2v9k3M4nLp7"
}Apply pushes to live channels
Pricing strategy
Per-listing knobs that constrain what the model can recommend. Floors and ceilings, weekday vs weekend multipliers, and lead-time curves are the most common.
/v1/listings/{id}/pricing/strategy·PUT/v1/listings/{id}/pricing/strategycurl -X PUT 'https://api.repull.dev/v1/listings/lst_abc123/pricing/strategy' \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{
"floor": 95,
"ceiling": 420,
"weekend_multiplier": 1.18,
"lead_time_curve": [
{ "days_out": 1, "multiplier": 0.85 },
{ "days_out": 7, "multiplier": 0.95 },
{ "days_out": 30, "multiplier": 1.00 },
{ "days_out": 90, "multiplier": 1.05 }
],
"weekday_overrides": {
"monday": 0.92,
"tuesday": 0.92,
"wednesday": 0.95,
"thursday": 1.00,
"friday": 1.18,
"saturday": 1.22,
"sunday": 1.05
}
}'Fields
floornumberThe minimum nightly rate. Recommendations are clamped at this value — the model will never suggest below it.
ceilingnumberThe maximum nightly rate. Same idea, opposite end. Useful for owner-imposed caps.
weekend_multipliernumberDefault: 1.0Friday + Saturday multiplier applied on top of the base recommendation. 1.18 = +18%.
lead_time_curveArray<{ days_out, multiplier }>Per lead-time multiplier. The model interpolates between points. Common pattern is to discount last-minute and slightly mark up far-out dates.
weekday_overridesRecord<weekday, multiplier>Per-weekday multiplier. Overrides weekend_multiplier when both are set on Friday/Saturday.
Direct channel push (advanced)
For power users who already run their own pricing engine and just want Repull as the delivery layer. Skip the recommendation pipeline entirely and push raw rates straight to a single channel.
GET /v1/channels/airbnb/listings/{id}/pricing— read the rates currently live on Airbnb.PUT /v1/channels/airbnb/listings/{id}/pricing— push raw rates to Airbnb.GET / PUT /v1/channels/plumguide/pricing— same pattern, Plum Guide./v1/channels/booking/...and/v1/channels/vrbo/...— coming next.
curl -X PUT 'https://api.repull.dev/v1/channels/airbnb/listings/lst_abc123/pricing' \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{
"rates": [
{ "date": "2026-06-12", "rate": 235, "currency": "EUR" },
{ "date": "2026-06-13", "rate": 248, "currency": "EUR" }
]
}'Direct push bypasses your strategy
Bulk operations (coming soon)
A bulk-apply endpoint for fanning a single decision policy across many listings is in flight. Until it ships, the right pattern is to fetch your listing IDs, fan out POST /v1/listings/{id}/pricing calls in parallel, and dedupe per-channel push errors on your side.
History audit (coming soon)
A pricing history endpoint that returns every recommendation, decision, applied rate, and per-channel push outcome for a listing-night is in flight. The audit_id returned by the apply call today will be the lookup key when it ships.
Common patterns
Apply all recommendations for the next 30 days
const today = new Date().toISOString().slice(0, 10)
const in30 = new Date(Date.now() + 30 * 86_400_000).toISOString().slice(0, 10)
const { data } = await repull.pricing.list('lst_abc123', { from: today, to: in30 })
await repull.pricing.decide('lst_abc123', {
decisions: data
.filter(n => !n.applied)
.map(n => ({ date: n.date, action: 'apply' as const })),
})Decline weekends, apply weekdays
Owner only wants AI managing weekday rates and keeps a fixed weekend rate.
const { data } = await repull.pricing.list('lst_abc123', { from, to })
await repull.pricing.decide('lst_abc123', {
decisions: data.map(n => {
const day = new Date(n.date).getUTCDay() // 0 Sun, 5 Fri, 6 Sat
const isWeekend = day === 5 || day === 6
return isWeekend
? { date: n.date, action: 'decline' as const, reason: 'owner-managed weekend' }
: { date: n.date, action: 'apply' as const }
}),
})Compare what was suggested vs what was applied
Each row in GET /v1/listings/{id}/pricingalready returns both. Diff them to render a "recommended vs live" chart.
const { data } = await repull.pricing.list('lst_abc123', { from, to })
const series = data.map(n => ({
date: n.date,
recommended: n.recommended_rate,
live: n.current_rate,
delta_pct: n.delta_pct,
}))
// Plot 'recommended' and 'live' on the same axis,
// shade the area between them by sign(delta_pct).Rate limits
Pricing endpoints follow the standard tier-based limits. See Rate Limits for per-tier numbers. Apply calls are higher cost than reads because each one fans out to multiple channel adapters — budget for one apply call per listing-night, not per underlying channel.