Docs/Channels/Airbnb

Update Airbnb Pricing

Push pricing to Airbnb: the pricing model, standard settings, length-of-stay records, rate plans, fees, currency, pricing rules, and per-date calendar operations. All three Airbnb pricing models are supported: Standard, Length of stay, and Rate plan.

PUT/v1/channels/airbnb/listings/:id/pricing

Parameters

idpathRequired

The Repull listing id (not the Airbnb listing id).

typestringRequired

Which pricing sub-resource to write: model | standard | los | rate-plan | fees | currency | rule | calendar. The rest of the body depends on it — see below.

Which endpoint to use

  • {id} is the Repull listing id — from GET /v1/properties or GET /v1/channels/airbnb/listings — not the Airbnb listing id. Repull translates it before calling Airbnb.
  • For nightly price, open/closed and min/max nights, the default is PUT /v1/availability/{propertyId} (or PATCH /v1/availability/batch for many properties): it writes the Repull calendar and pushes the change to the channels Repull can write a calendar to — Airbnb and Booking.com — in one step. Use this endpoint for settings that exist only on Airbnb. Writes here go to Airbnb alone.

API sync is authorised per listing

Airbnb turns API sync on one listing at a time, not once for the account. Each listing carries its own sync category, and a listing whose category is none is closed to the API — Airbnb refuses every write to it even though the account is connected and every other listing on it writes fine. Reconnecting the Airbnb account does not change a listing's sync category. Only someone with access to the listing on Airbnb can turn sync on for it, on the listing itself.

  • sync_all — Repull manages content, rates and availability. Every write on this page works.
  • sync_rates_and_availability — Repull manages rates and availability; listing content is managed by the host on Airbnb.
  • none — the listing is not connected to Repull on Airbnb at all. Every write returns 403 listing_not_api_connected and nothing is sent to Airbnb, so nothing is partially applied.
  • To tell which is which, read GET /v1/channels/airbnb/listings: every entry of each listing's connections[] carries syncCategory (one of the three above, or null if it has never been reported) and writable — false exactly when syncCategory is none. Check writable before a write and you never send one that cannot land. Full detail: https://repull.dev/docs/errors/listing_not_api_connected

Body by type

  • model — {"type": "model", "modelType": "STANDARD"}. modelType is STANDARD, LOS_RECORD or RATE_PLAN.
  • standard — {"type": "standard", "settings": {...}}. Standard pricing settings. The object replaces the current one, so GET the pricing first, change it, and PUT the whole object back.
  • los — {"type": "los", "records": [{"check_in_date": "2026-09-15", "guest_count": 2, "los_data": [[1, 120], [7, 700]]}]}. A non-empty array; each record needs check_in_date, guest_count (at least 1) and los_data as [nights, price] pairs.
  • rate-plan — {"type": "rate-plan", "settings": {...}}. Rate-plan pricing settings; replaces the current object.
  • fees — change the listing's fees. Airbnb replaces the whole fee list on every write: send {"type": "fees", "settings": {"standard_fees": [...]}} and any fee you leave out is deleted. Use fees instead and Repull keeps the rest for you: {"type": "fees", "fees": [{"fee_type": "PASS_THROUGH_MANAGEMENT_FEE", "amount": 10, "amount_type": "percent"}]} sets that one fee and keeps every other; "amount": null removes just that fee. The response is the listing's fees as Airbnb holds them afterwards. Send fees or settings, not both.
  • currency — {"type": "currency", "currency": "USD"}. An ISO 4217 code in capitals.
  • rule — {"type": "rule", "rule": {...}}. Adds one pricing rule to the listing.
  • calendar — {"type": "calendar", "operations": [...]}. Per-date price and restrictions; operation fields below.

Fees

The same units GET …/pricing returns, so a fee you read can be written back unchanged.

  • amount — for a flat fee, the amount in the listing currency × 1,000,000 (160000000 = 160.00). For a percent fee, a whole percent of the rent (10 = 10%). Percent is accepted for management and resort fees. null removes the fee.
  • fee_type — PASS_THROUGH_CLEANING_FEE, PASS_THROUGH_SHORT_TERM_CLEANING_FEE, PASS_THROUGH_PET_FEE, PASS_THROUGH_SECURITY_DEPOSIT, PASS_THROUGH_MANAGEMENT_FEE, PASS_THROUGH_RESORT_FEE, PASS_THROUGH_COMMUNITY_FEE, PASS_THROUGH_LINEN_FEE. One fee per type.
  • amount_type — flat or percent. charge_type — PER_GROUP, PER_PERSON or PER_PET. charge_period — PER_BOOKING or PER_NIGHT. offline — true when the host collects it outside Airbnb. Each defaults to the existing fee's value, else flat / PER_GROUP / PER_BOOKING / false.
  • To update one fee without touching the others, send only that fee in fees. To change several, send them together — one write, one read-back.

Calendar operations

  • Dates — either dates (a non-empty array of YYYY-MM-DD dates or inclusive ranges YYYY-MM-DD:YYYY-MM-DD) or start_date + end_date (inclusive, sent together, end_date on or after start_date). Not both.
  • daily_price — nightly price, a number ≥ 0 in the listing currency.
  • availability — available reopens the dates, unavailable blocks them (stop-sell), default falls back to the listing rules.
  • busy_subtype — why a blocked date is blocked: BLOCKED_BY_HOST or OUTSIDE_RESERVATION. Airbnb requires it whenever availability is unavailable; if you leave it out, BLOCKED_BY_HOST is sent. Use OUTSIDE_RESERVATION for dates held by a booking made on another channel.
  • min_nights, max_nights — whole numbers from 1 to 1125 (Airbnb's limit); max_nights cannot be lower than min_nights.
  • closed_to_arrival, closed_to_departure — JSON booleans (true / false, not strings).
  • notes — free text.
  • operations must contain at least one operation. Unknown fields are refused rather than ignored: sending price returns 422 invalid_params naming operations.0.price (the field is daily_price), so a misspelling can never look like a successful write.

Errors

A successful write returns 200 with Airbnb's result.

  • 422 invalid_params — the body failed validation before anything was sent to Airbnb. field names the field (for example operations.0.max_nights), value_received echoes it and fix says what to send.
  • 422 airbnb_rejected — Airbnb refused the change. message carries Airbnb's own reason. Correct the request; sending the same body again is refused again.
  • 403 listing_not_api_connected — Airbnb API sync is off for this listing (its sync category is none), so Airbnb accepts no writes to it and nothing was sent. Reconnecting the Airbnb account does not fix this — the host has to turn API sync on for that one listing inside Airbnb. See the section above, and https://repull.dev/docs/errors/listing_not_api_connected
  • 403 connection_reauth_required — the host's Airbnb authorization expired or was revoked, or Airbnb refused to refresh it. This takes the whole account down, not one listing. Retrying will not help. Reconnect Airbnb at https://repull.dev/dashboard/connections (or POST /v1/connect/airbnb), then retry.
  • 403 listing_inactive — the listing is inactive. Activate it with PATCH /v1/listings/{id} and {"active": true}, then retry.
  • 404 not_found — no Airbnb-connected listing with this id in your workspace. Check the id is the Repull listing id. 404 no_connection — the workspace has no Airbnb connection at all.
  • 429 airbnb_rate_limited — Airbnb is rate-limiting writes for this host. Wait retry_after seconds when present, otherwise back off exponentially, and put many dates in one operations array instead of one call per date.
  • 502 airbnb_error — Airbnb had an outage or timed out. Nothing about the request needs to change: retry with backoff.

Example

# Add a 10% management fee and keep every other fee (4118 is the Repull listing id)
curl -X PUT https://api.repull.dev/v1/channels/airbnb/listings/4118/pricing \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "fees", "fees": [{"fee_type": "PASS_THROUGH_MANAGEMENT_FEE", "amount": 10, "amount_type": "percent"}]}'

# Set the cleaning fee to 160.00 and remove the pet fee
curl -X PUT https://api.repull.dev/v1/channels/airbnb/listings/4118/pricing \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "fees", "fees": [{"fee_type": "PASS_THROUGH_CLEANING_FEE", "amount": 160000000, "amount_type": "flat"}, {"fee_type": "PASS_THROUGH_PET_FEE", "amount": null}]}'

# Update the base nightly rate
curl -X PUT https://api.repull.dev/v1/channels/airbnb/listings/4118/pricing \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "standard", "settings": {"default_daily_price": 250}}'

# Set price and stay limits for specific dates
curl -X PUT https://api.repull.dev/v1/channels/airbnb/listings/4118/pricing \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "calendar",
    "operations": [
      {
        "dates": ["2026-06-01", "2026-06-02"],
        "availability": "available",
        "daily_price": 300,
        "min_nights": 2,
        "max_nights": 14,
        "closed_to_arrival": false,
        "closed_to_departure": false
      }
    ]
  }'

# Block a range held by a booking made on another channel
curl -X PUT https://api.repull.dev/v1/channels/airbnb/listings/4118/pricing \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type": "calendar", "operations": [{"dates": ["2026-07-01:2026-07-04"], "availability": "unavailable", "busy_subtype": "OUTSIDE_RESERVATION"}]}'

Response

// 422 — a field failed validation; nothing was sent to Airbnb
{
  "error": {
    "code": "invalid_params",
    "message": "`operations.0.max_nights` is invalid: Number must be less than or equal to 1125",
    "fix": "Send a whole number of nights between 1 and 1125, no lower than `min_nights`.",
    "field": "operations.0.max_nights",
    "value_received": "2000",
    "docs_url": "https://repull.dev/docs/errors/invalid_params",
    "request_id": "req_01J5X7Y8Z9ABCDEF12345678"
  }
}
AI