inventory_not_in_rate_update

A Booking.com rates update carried `roomsToSell`. Inventory belongs to the availability write.

HTTP 422The request was understood but refused as sent. Change it before retrying.

When it fires

A Booking.com rate write carried inventory. PUT /v1/channels/booking/availability with type: "rates" writes prices and restrictions; roomsToSell on one of its updates is refused, and nothing is pushed to Booking.com.

The refusal names the offending item — field: "updates[0].roomsToSell" — so a batch of fifty tells you which one to change.

Response shape

Every Repull error follows the same envelope. The code is stable and safe to switch on.

{
  "error": {
    "code": "inventory_not_in_rate_update",
    "message": "<human-readable explanation of what went wrong>",
    "docs_url": "https://repull.dev/docs/errors/inventory_not_in_rate_update"
  }
}

How to fix

  1. Take roomsToSell out of the rates update and send the prices on their own.
  2. Send the inventory as a second call to the same endpoint with `type: "availability"`, where rooms to sell is `availableRooms` and the stop-sell flag is `closed`.
  3. Neither write implies the other: pricing a night does not open it for sale, and opening it does not price it. Send both when you mean both.

Common gotchas

  • The two writes use different field names. Inventory is roomsToSell nowhere — on the availability write it is availableRooms.
  • A night that is open for sale with no price on the rate plan you sell does not appear on Booking.com at all. If a property went quiet after a rates-only backfill, check the availability side too.
  • Dates are inclusive at both ends on both writes: { "start": "2026-11-04", "end": "2026-11-04" } is exactly one night. See Update Booking.com Pricing.

Examples

curl

# Bad: inventory on a rates write
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-11-04", "end": "2026-11-04"}, "price": 180, "currency": "USD", "occupancy": 4, "roomsToSell": 1}]}'

# {
#   "error": {
#     "code": "inventory_not_in_rate_update",
#     "message": "A rates update carries prices only. Rooms to sell belong to the availability write.",
#     "field": "updates[0].roomsToSell",
#     "docs_url": "https://repull.dev/docs/errors/inventory_not_in_rate_update"
#   }
# }

# Good: the price...
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-11-04", "end": "2026-11-04"}, "price": 180, "currency": "USD", "occupancy": 4}]}'

# ...and the inventory, as a second call
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-11-04", "end": "2026-11-04"}, "availableRooms": 1, "closed": false}]}'

TypeScript

// The SDK has no Booking.com availability method, so call the endpoint directly.
const endpoint = 'https://api.repull.dev/v1/channels/booking/availability'
const headers = {
  Authorization: `Bearer ${process.env.REPULL_API_KEY}`,
  'Content-Type': 'application/json',
}
const night = { roomId: '123456701', rateId: '98765', dateRange: { start: '2026-11-04', end: '2026-11-04' } }

// Prices go on their own.
const rates = await fetch(endpoint, {
  method: 'PUT',
  headers,
  body: JSON.stringify({
    type: 'rates',
    property_id: '1234567',
    updates: [{ ...night, price: 180, currency: 'USD', occupancy: 4 }],
  }),
})

if (!rates.ok) {
  const { error } = await rates.json()
  if (error.code === 'inventory_not_in_rate_update') {
    // error.field names the update that carried it, e.g. "updates[0].roomsToSell"
    console.error('Move inventory to the availability write:', error.field)
  }
  throw new Error(`${error.code}: ${error.message}`)
}

// Rooms to sell go as a second call.
await fetch(endpoint, {
  method: 'PUT',
  headers,
  body: JSON.stringify({
    type: 'availability',
    property_id: '1234567',
    updates: [{ ...night, availableRooms: 1, closed: false }],
  }),
})

If you're an AI agent

A rates update carried roomsToSell. Remove it, send the prices alone, then send the inventory as a second call to the same endpoint with type: 'availability' using availableRooms (and closed for stop-sell). error.field names the update that carried it.

Hit an error that isn't covered? Email hello@repull.dev with the request id from the response headers.

AI