Properties & listings on Booking.com
A Booking.com property is a building. Its rooms are what guests book, and each room maps to one Repull listing. Getting that shape right is what makes every other Booking.com endpoint make sense — including which of the two id spaces each one takes.
The model
When a host connects Booking.com they claim a property by its hotel id. We import its rooms. The last step of the connect flow is room mapping: the host says which Repull listing each room corresponds to.
Booking.com property "hotel_id": 5432505 ← the building
└── room "roomBookingId": 543250501 ← what a guest books
└── Repull listing "listingId": 28028 ← what you address in the APIA one-room villa gives you the simple case above. A twenty-unit aparthotel is a single property holding twenty rooms mapped to twenty listings — that is normal, not an edge case. The reverse happens too: the same unit can be published under more than one Booking.com property, usually because it was re-listed over time.
- One property → many listings, one per mapped room.
- One listing → possibly several properties, if it is published under more than one.
- A room that is not mapped yet belongs to no listing, and its reservations have nowhere to land.
Which id each endpoint takes
This is the one thing worth reading twice. Two endpoints with properties in the path take a Repull listing id, not a Booking.com hotel id. Passing the wrong one gets you a 404 that looks like a permissions problem.
| Endpoint | Id it takes |
|---|---|
GET /v1/channels/booking/properties | none — lists everything |
GET /v1/channels/booking/properties/{id} | Repull listing id |
GET /v1/channels/booking/properties/{id}/rooms | Repull listing id |
GET/PUT /v1/channels/booking/listings/{id}/pricing | Repull listing id |
PUT /v1/channels/booking/availability | Booking.com hotel id (property_id) |
GET/POST /v1/channels/booking/content | Booking.com hotel id (property_id) |
The rule of thumb
property_id as a query or body field takes a Booking.com hotel id. The naming is historical; changing it would break every integration already built on it, so the error messages name the id space instead.Reading the map
One call gives you the whole picture — every property, and the listings under each.
curl https://api.repull.dev/v1/channels/booking/properties \ -H "Authorization: Bearer sk_live_YOUR_KEY"
[
{
"connectionId": "775",
"hotelId": "5432505",
"active": true,
"syncEnabled": true,
"mappingStatus": "mapped",
"listings": [
{
"listingId": "28028",
"name": "Villa MarSalada",
"city": "La Frontera",
"roomBookingId": "543250501",
"roomName": "Room MarSalada",
"mappedVia": "room"
}
]
},
{
"connectionId": "776",
"hotelId": "5432506",
"active": true,
"mappingStatus": "unmapped",
"listings": []
}
]Each property appears exactly once. listings[].listingId is what you pass to the listing-addressed endpoints above; hotelId is what you pass as property_id to the hotel-addressed ones; listings[].roomBookingId is the roomId an availability or rate write takes.
When a property shows no rooms
A property with "mappingStatus": "unmapped" and an empty listings array is connected but not finished. The host claimed the hotel and we imported its rooms, but nobody has said which listing each room is. Until they do:
- the listing-addressed endpoints have no listing id to accept, so they answer
404 not_found; - reservations arriving for those rooms have no listing to attach to.
The fix is to finish room mapping. Read the rooms awaiting a decision, then submit the choices:
# Rooms imported for the connect session, with their mapping state
curl "https://api.repull.dev/v1/connect/booking/rooms?sessionId=cs_..." \
-H "Authorization: Bearer sk_live_YOUR_KEY"
# Map each room to a listing (or ask us to create one)
curl -X POST https://api.repull.dev/v1/connect/booking/map-rooms \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "cs_...",
"mappings": [
{ "roomId": 1333, "listingId": 28028 },
{ "roomId": 1334, "create": true }
]
}'Hosts going through the hosted connect page do this themselves on the last screen — see Connect Booking.com. Re-check GET /v1/channels/booking/properties afterwards: the property should read mapped, with its listings attached.
An unmapped property is still listed
mappingStatus tells you which of the two you have.When one listing is under several properties
Uncommon, but real. When it happens, a listing-addressed endpoint has to decide which property you meant:
- Reads use the oldest mapping and hand you the rest in
otherHotelIds, so you can tell it happened. - Writes refuse with
409 ambiguous_booking_mappingand push nothing. Guessing which property gets your rates is not a mistake you would find quickly.
Either way, ?hotel_id= settles it:
curl -X PUT "https://api.repull.dev/v1/channels/booking/listings/6001/pricing?hotel_id=8000002" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"updates": [
{
"roomId": "800000201",
"rateId": "1234567",
"dateRange": { "start": "2026-10-01", "end": "2026-10-07" },
"price": 180,
"currency": "EUR"
}
]
}'roomId and rateId come from GET /v1/channels/booking/properties/{id}/rooms, which returns each room with every rate plan under it.
Troubleshooting
| What you see | What it means |
|---|---|
Empty array from /properties | No Booking.com property is connected to this workspace at all. Start with Connect Booking.com. |
mappingStatus: "unmapped" | Connected, rooms imported, mapping unfinished. Submit POST /v1/connect/booking/map-rooms. |
404 not_found on a listing-addressed path | Either you passed a Booking.com hotel id where a Repull listing id belongs, or that listing has no mapped room. The message says which. |
403 listing_inactive | The listing is mapped but deactivated. It keeps syncing; activate it with PATCH /v1/listings/{id}. |
409 ambiguous_booking_mapping | The listing is published under several properties. Add ?hotel_id=; the error lists the valid ids. |
A listing missing from listings[] | Inactive listings are left out of collections. Find them with GET /v1/listings?status=inactive. |
Related: Manage Properties, Update Pricing, Push Availability, Identifiers.