Integration guide

The Booking.com API: how access works, and what it actually lets you do

Written for the engineer or technical founder pointed at Booking.com's Connectivity APIs. It covers how partner designation and per-property connection work, the data model that everything else depends on, and the two or three behaviours that make a Booking.com rate update succeed on paper and change nothing in practice.

What the Booking.com API is

Booking.com's APIs are built for connectivity providers: the channel managers and property management systems that keep accommodation in sync on behalf of many properties at once. They are not consumer APIs, there is no public search or booking surface for third parties, and there is no developer portal you sign up to.

Practically it is several product surfaces under one partnership — availability and rates, reservations, property and room setup, content, messaging, reviews, and financial charges. They behave differently from one another, they are entitled separately, and parts of the older surface are XML rather than JSON. Coming from Airbnb, almost none of your assumptions transfer.

How do I get Booking.com API access?

Three layers, granted by three different parties, exactly as with Airbnb but shaped differently.

  1. Booking.com designates your company a connectivity partner. You apply, you are reviewed commercially and technically, and there is a certification step against the surfaces you intend to use. This is a company-level relationship measured in months.
  2. You are issued credentials for a machine account.Unlike Airbnb's per-host OAuth tokens, one machine account acts for every property connected to you. That single credential is the blast radius for your whole book of business, and it changes how you read errors — see the note below.
  3. Each property connects you from its own Extranet. The host signs in to the Booking.com Extranet, opens the connectivity provider list, finds your provider by name, and clicks Connect. Until they do, your machine account cannot see that property at all. They will also need their numeric Hotel ID to hand.

Capabilities are granted separately, per surface

Partner designation is not a single switch. Individual capabilities — content being the one that catches people — are enabled separately for the partner. A property can be live, taking reservations, accepting rate and availability writes, while content calls answer 403. Nothing is broken; that capability was never granted. Check which surfaces you are actually entitled to before you scope work that depends on one.

One machine account means a 401 is never a single host's problem

Because every property runs through the same credential, the error you get tells you which layer failed — and confusing the two layers is how a token blip turns into a mass disconnection in your own database.

A 403 naming invalid credentials for one hotel means that host revoked you in their Extranet: a genuine, property-level disconnection. A 401 is the machine account itself and affects every property at once — global, transient, and never a reason to mark anybody disconnected. A 403 without a credentials code is ambiguous and should change nothing.

Our own reconciler only ever flags a connection as disconnected on a hotel-level 403 with an explicit credentials-invalid code. Everything else — 401s, 429s, 5xx, timeouts, network errors, parse failures — is classified unknown and touches no state. A false positive during a Booking.com outage is far more expensive than a missed one.

Through Repull the host-facing half is one hosted session that carries your branding; they complete the Extranet step and paste their Hotel ID, and you get a connection back. The walkthrough is on Connect Booking.com.

curl -X POST 'https://api.repull.dev/v1/connect/booking' \
  -H 'Authorization: Bearer sk_live_YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{ "redirectUrl": "https://yourapp.com/connected" }'

Properties, rooms and rate plans

Get this right and the rest of Booking.com follows. Get it wrong and every endpoint feels arbitrary.

Booking.com property   "hotel_id": 5432505        ← the building
└── room               "roomBookingId": 543250501 ← what a guest books
    └── rate plan      "rateId": 98765            ← the terms it sells on
        └── price at an occupancy                ← what you actually write

A property is a building. Rooms are what guests book. Rate plans are the commercial terms a room sells on, and a price belongs to a (room, rate plan, date, occupancy) tuple — not to a night. A one-bedroom villa is the simple case; a twenty-unit aparthotel is a single property holding twenty rooms, which is normal rather than an edge case.

The same unit can also appear under more than one Booking.com property, usually because it was re-listed over time, and a room that has not been mapped to one of your listings belongs to nothing — its reservations have nowhere to land. Map rooms during the connect flow, not afterwards.

Two id spaces in paths that read the same

Booking.com integrations carry a Booking hotel id and your own listing id side by side, and passing the wrong one produces a 404 that reads exactly like a permissions problem.

In Repull the rule of thumb is: an id in the path is a Repull listing id, while property_id as a query or body field is a Booking.com hotel id. So GET /v1/channels/booking/properties/{id}/rooms takes a listing id, and PUT /v1/channels/booking/availability takes a hotel id. The naming is historical and changing it would break every integration already built on it, so the error messages name the id space instead. Full table on Properties and listings on Booking.com.

Can I update rates through the Booking.com API?

Yes, and this is the most-used surface in the whole partnership. You write a price for a room on a rate plan over a date range, optionally with length-of-stay and arrival restrictions in the same 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": "rates",
    "property_id": "1234567",
    "updates": [{
      "roomId": "123456701",
      "rateId": "98765",
      "dateRange": { "start": "2026-11-04", "end": "2026-11-04" },
      "price": 210,
      "currency": "USD",
      "occupancy": 4
    }]
  }'

roomId and rateId come from GET /v1/channels/booking/properties/{id}/rooms. Everything else on the request — and there is more of it than you expect — is on Update Booking.com pricing.

Why did my Booking.com price update do nothing?

This is the question that brings people to this page, and there are two independent answers. Both look like success.

The occupancy is part of the key, not a preference

Booking.com does not store “the price of this night”. It stores a price for a night at a party size on one rate plan. So the occupancy you send decides which price you are overwriting. Every rate amount goes out against one, whether you named it or not.

Repull resolves the occupancy from Booking.com's own data for the (room, rate plan) pair when you omit it, echoes both the value used and where it came from, and refuses the write with a 422 when it cannot be resolved. A rate amount is never sent blind.

The acknowledgement is not a confirmation

Booking.com usually answers a rate write with a bare acknowledgement carrying no per-date status. The body is literally:

{"ok": ""}

That is a receipt for the request, not the state of the price

Nothing in that response says the price is live on a single one of the dates you sent. Any integration that reports “all updates applied” on the strength of it is guessing, and the one case where it is wrong — an occupancy mismatch — is exactly the case it cannot see.

The only honest answer is to read the dates back and compare. Writes are applied asynchronously, so the read-back has to wait a short settle delay, and it costs one extra read per call. Repull does it by default and reports one of four states: verified, unverified (the read-back was skipped or unavailable — unknown, not applied), mismatch (naming the dates and what Booking.com holds instead), or rejected. Pass verify: false for a long backfill you intend to reconcile separately.

Date ranges, and the night you lose

Underneath, the availability and rates XML takes a range whose to date is not written— it is an exclusive bound, the way a checkout date is exclusive of the last night. Most calendar surfaces you will have integrated before treat both ends as nights. So the natural reading of “1 to 7 August” is seven nights and the wire meaning is six, and the night you silently drop is the last one of every range you write.

It is a one-line conversion and a week-long bug, because it only ever costs you the final night: the calendar looks broadly right, a spot check passes, and the gap shows up as a missed booking rather than an error.

Pick one convention and convert at the boundary

Repull's surface is inclusive at both ends — on rates, on availability and on restrictions alike — so start equal to end is exactly one night, and 2026-11-04 to 2026-11-07 is four nights. The conversion to the exclusive wire format happens once, inside, so it cannot be got wrong per call site. Whatever you build, make the same choice once rather than per endpoint.

Inventory is a separate write

Pricing a night does not open it for sale, and opening it does not price it. Rooms to sell and the stop-sell flag are their own update type; sending them on a rate update is refused rather than silently dropped.

# Close a night: zero rooms to sell, stop-sell on
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": 0,
      "closed": true
    }]
  }'

Detail on Push availability to Booking.com. If you would rather write a calendar once and have it land on every connected channel, that is PUT /v1/availability/{propertyId}, with PATCH /v1/availability/batch for many properties at once.

Restrictions that exist, and ones that do not

Minimum and maximum stay (both stay-date and arrival-date based), closed to arrival and closed to departure are all real and settable per room, rate plan and date range.

Several restrictions people expect are simply not in the notification Booking.com accepts — an exact stay length on arrival, and minimum or maximum advance reservation among them. The right behaviour is to refuse them loudly. A restriction that is accepted and then not sent is the one failure you cannot see in a response, so Repull answers 422 naming the field rather than dropping it. See restriction_not_supported and Minimum stay and restrictions.

Reservations, messaging, reviews and charges

The capability matrix sets Airbnb and Booking.com side by side, marking partial as partial rather than rounding it up.

Why does the Content API return 403?

Because content is its own product surface with its own entitlement, on its own base path, separate from the availability, rates and reservations surfaces. A property can be fully live — taking bookings, accepting every rate and availability write you send — while every content call for that same property answers 403.

When that happens, the instinct is to suspect the token, then the property id, then the host's Extranet permissions. It is usually none of those. The capability was not granted to you for that surface, and no amount of reconnecting changes it. Confirm which capabilities your partnership actually carries before you scope photo or description management into a release.

Content itself, where it is available, covers photos, descriptions, amenities, facilities and policies, at property or room level — and Booking.com reviews text changes before they appear, so a write is the start of a process rather than the end of one. Content and photos.

What it takes to build this yourself

  1. Partner designation and certification. Months, with commercial review and a technical certification step per surface. You cannot promise a customer a date.
  2. A shared-credential security model. One machine account for every property you serve. Rotation, storage, and an error classifier careful enough that a global 401 during an outage cannot mass-disconnect your customers.
  3. The model and the mapping. Properties to rooms to rate plans to your own listings, including multi-room properties, re-listed units, and unmapped rooms whose reservations have nowhere to go.
  4. Write verification. Because the acknowledgement proves nothing, a correct integration reads back and reconciles. That is an extra call, a settle delay and a state machine, on the hottest path you have.
  5. Convention mismatches. Exclusive date bounds, occupancy-keyed prices, inventory split from rates, restrictions that do not exist, XML where you expected JSON.
  6. Ongoing breakage. Same as every partner API: it does not converge to zero.

The honest summary is that Booking.com is a heavier integration than Airbnb and shares almost none of its assumptions — different auth model, different data model, different date semantics, different definition of a successful write. Teams that have just finished Airbnb consistently underestimate it. The Airbnb API guide is the comparison.

Where Repull fits

Repull is one REST API and one key across Booking.com, Airbnb, VRBO, Plumguide and 50+ property management systems. We hold the partner relationships; properties connect themselves through a hosted flow that carries your branding.

Start at the quickstart, or read the channels overview. If you are a platform embedding this for your own customers rather than integrating for yourself, the guide for platforms covers that model question by question.

Frequently asked questions

How do I get Booking.com API access?

Booking.com grants API access to designated connectivity partners, not to individual integrators. A company applies, is reviewed, and is issued credentials for a machine account that talks to Booking.com on behalf of many properties. Each property then has to connect that named provider from its own Extranet before the machine account can see it. The partner designation is a commercial process measured in months; the per-property connect step takes a host about five minutes.

Why did my Booking.com price update do nothing?

Most often because the rate amount named an occupancy the rate plan does not price at. Booking.com does not store the price of a night; it stores the price of a night at a party size on one rate plan. Send an occupancy above the maximum the rate plan prices at and Booking.com accepts the request and declines the amount without saying so — the night keeps whatever it held before, often 0.00, and the acknowledgement is indistinguishable from a successful write. Send one below it and you get a 400 instead. Read the rate plan occupancy back from Booking.com rather than assuming your own listing capacity.

Does a Booking.com rate write confirm the price is live?

No. Booking.com usually answers a rate write with a bare acknowledgement whose body is literally {"ok": ""}. That is a receipt for the request, not confirmation of the price. The only way to know is to read the dates back afterwards and compare. Repull does that read-back by default and reports verified, unverified, mismatch or rejected rather than claiming all updates applied.

Why is my last night not being updated on Booking.com?

Because the underlying XML date range does not include its to date, while most other calendar surfaces you will have integrated are inclusive. Send 1 to 7 August expecting seven nights and you write six. Decide which convention your own API exposes and convert once, at the boundary. Repull exposes an inclusive range at both ends — start equal to end is exactly one night — and does the conversion internally.

Why does the Booking.com Content API return 403 when reservations work fine?

Because capabilities are granted separately. Content sits on its own product surface with its own entitlement, so a property can be fully live for reservations, availability and rates while every content call answers 403. It is not a token problem and not a bad property id, and no amount of reconnecting will change it — the capability has to be enabled for the partner and the property.

What does a Booking.com integration cost?

Booking.com does not charge for connectivity itself; the cost is the partner designation, the engineering, and operating the integration. For what an integration through Repull costs, email hello@repull.dev with your property count and the channels you need and we will quote against it.

Talk to us about Booking.com access

Tell us how many properties you expect to connect, which surfaces you need — rates, content, messaging, financials — and what else you are connecting alongside Booking.com. We will come back with what the integration looks like and what it costs.