Docs/Channels/Booking.com

Minimum Stay & Restrictions

Set a minimum stay, a maximum stay, and closed-to-arrival / closed-to-departure on a Booking.com room and rate plan — on their own, or in the same call as a price. The response tells you which of the two actually landed.

PUT/v1/channels/booking/availability

What you can set

Every field is optional. Omit one and that restriction is left exactly as it is — nothing you leave out is touched.

minStayinteger

Minimum nights for a stay covering these dates.

maxStayinteger

Maximum nights for a stay covering these dates.

minStayArrivalinteger

Minimum nights for a stay that STARTS on these dates.

maxStayArrivalinteger

Maximum nights for a stay that starts on these dates.

closedToArrivalboolean

true: guests may not check in on these dates. false clears it.

closedToDepartureboolean

true: guests may not check out on these dates. false clears it.

Three restrictions cannot be written through the API

exactStayArrival, minAdvanceRes and maxAdvanceRes return 422 restriction_not_supported naming the field, and nothing is sent. Booking.com has no way to receive them; set them on the rate plan in the Booking.com Extranet.

They are refused rather than dropped on purpose: a restriction that is accepted and then not sent is the one failure you cannot see in a response.

Set a minimum stay

A restriction-only write needs no price. roomId and rateId come from GET /v1/channels/booking/properties/{id}/rooms. Dates are inclusive at both endsstart equal to end is exactly one night.

curl -X PUT "https://api.repull.dev/v1/channels/booking/availability" \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "availability",
    "property_id": "1234567",
    "updates": [{
      "roomId": "123456701",
      "rateId": "98765",
      "dateRange": { "start": "2026-07-01", "end": "2026-07-31" },
      "restrictions": { "minStay": 3, "closedToArrival": true }
    }]
  }'

A one-night minimum is no minimum

Booking.com stores minStay: 1 as 0 and reports it back as 0. Repull treats that as applied rather than as a mismatch, so setting a minimum of one night is not a permanent “did not land”.

Set a price and a restriction together

Send both in one type: "rates"update. Booking.com receives them as two writes — a rate amount and a restriction notification — so the response reports each separately. A rate amount also needs an occupancy; omit it and Repull resolves it from Booking.com's own data and echoes the value back. See Update Booking.com Pricing.

curl -X PUT "https://api.repull.dev/v1/channels/booking/availability" \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "rates",
    "property_id": "1234567",
    "updates": [{
      "roomId": "123456701",
      "rateId": "98765",
      "dateRange": { "start": "2026-07-01", "end": "2026-07-07" },
      "price": 182,
      "currency": "EUR",
      "occupancy": 4,
      "restrictions": { "minStay": 4 }
    }]
  }'

Reading the result

Booking.com acknowledges a write without saying what happened to each night, so Repull reads the nights back off Booking.com afterwards — prices and restrictions in one read — and reports what is actually live.

verified

Read back off Booking.com. Every night carries what was sent.

mismatch

Read back, and some nights do not. The verification rows name them.

partial

One half landed and the other did not. Read price.applied and restrictions.applied.

rejected

Booking.com refused everything that was sent. Nothing changed.

unverified

Booking.com acknowledged the request and no read-back ran. An unknown, not a success.

What a partial result looks like

The price was written and verified; the minimum stay was refused. This is a 200 — a half that landed is never reported as a failure — and restrictions.rejection.messageis Booking.com's own reason for the half that did not.

{
  "propertyId": "1234567",
  "requested": 1,
  "applied": "partial",
  "occupancy": [
    { "index": 0, "roomId": "123456701", "rateId": "98765", "value": 4, "source": "request" }
  ],
  "price": {
    "requested": 1,
    "applied": "verified",
    "verification": {
      "ran": true,
      "matched": 7,
      "mismatched": 0,
      "rows": [
        { "date": "2026-07-01", "expectedPrice": 182, "bookingPrice": 182, "match": true }
      ]
    },
    "errors": []
  },
  "restrictions": {
    "requested": 1,
    "fields": ["minStay"],
    "dates": [
      { "index": 0, "roomId": "123456701", "rateId": "98765", "start": "2026-07-01", "end": "2026-07-07", "fields": ["minStay"] }
    ],
    "applied": "rejected",
    "verification": { "ran": false, "skippedReason": "not_requested", "matched": 0, "mismatched": 0, "unreported": 0, "rows": [] },
    "errors": [],
    "rejection": {
      "status": 400,
      "message": "Minimum stay is not supported for rate 98765 on room 123456701",
      "ruid": "UmFuZG9tSVYkc2RlIyh9YW1"
    }
  }
}

Act on it in that order: check applied, and when it is partial read each half. The half that landed needs nothing. The half that did not carries rejection.message— Booking.com's words, not a paraphrase — and rejection.ruid, their request id, which Booking.com connectivity support can look up.

const result = await res.json()

if (result.applied === 'partial') {
  // Do NOT re-send the half that already landed.
  if (result.price.applied !== 'verified') {
    console.warn('prices did not land:', result.price.rejection?.message)
  }
  if (result.restrictions.applied !== 'verified') {
    console.warn('restrictions did not land:', result.restrictions.rejection?.message)
    console.warn('affected nights:', result.restrictions.dates)
  }
}

Skip the read-back when you do not need it

Send verify: false on a rates write to skip the read and save a call to Booking.com. applied is then unverified — which means unknown, not applied.

Clearing a restriction

Send false to clear a closed-to-arrival or closed-to-departure flag, and minStay: 1 (or 0) to drop a minimum stay. Omitting the field does not clear it — it leaves whatever is already set.

curl -X PUT "https://api.repull.dev/v1/channels/booking/availability" \
  -H "Authorization: Bearer sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "availability",
    "property_id": "1234567",
    "updates": [{
      "roomId": "123456701",
      "rateId": "98765",
      "dateRange": { "start": "2026-07-01", "end": "2026-07-31" },
      "restrictions": { "minStay": 1, "closedToArrival": false }
    }]
  }'

When it fails

  • 422 restriction_not_supported — the restriction cannot be written through the API. field names it; nothing was sent.
  • 422 booking_rejected — Booking.com refused the whole write. message is their reason, booking_ruid their request id. Resending the same body is refused again.
  • 429 booking_rate_limited — back off and put more dates into one request.
  • 502 booking_error — Booking.com had an outage. The request is fine; retry with backoff.
  • 404 not_found — the property is not connected to your workspace, which is also the answer for an id that does not exist.

A partial result is never an error status

If one half lands and the other is refused you get 200 with applied: "partial". An error status means nothing was applied at all.
AI