Reservations
Book stays, read and search them, change dates and guests, cancel under the hotel's policy, and add extras.
A reservation made through the API is a normal ChatBeds booking: it is priced by the hotel's pricing engine, shows on the hotel's tape chart, alerts the staff, and carries the source PARTNER:<partner> plus your own external_ref. It is booked as pay at the hotel; take money with a payment link or record a payment you took yourself.
The reservation object
Every operation on this page returns a reservation in this shape (search returns a list of them).
| Field | Type | Meaning |
|---|---|---|
id | uuid | Store it: every later call uses it |
ref | string | The short reference the hotel sees and the guest is told, such as A589DF |
property_id | uuid | |
status | string | confirmed, checked_in, checked_out, cancelled or no_show. A booking made elsewhere at the hotel can also be pending; it holds its room like a confirmed one |
source | string | Who made it: PARTNER:<partner> for you; other values for the front desk, the booking page, other partners |
external_ref | string or null | Your reference, as you sent it |
arrival, departure | date | First night; day of departure |
nights, adults, children | integer | |
guest | object | first_name, last_name, email, phone |
room_type | object or null | {"id", "name"} |
unit | object or null | {"id", "name"} once a room is assigned; null until the hotel assigns one |
rate_plan | object or null | {"id", "name"}, or null for the room type's own rate |
currency | string | |
total | number | Everything charged on the folio (room, extras, fees, tax, charges) |
paid | number | Payments received |
balance | number | total minus paid. Negative means the hotel owes the guest a refund |
cancellation | object or null | When cancelled: {"fee", "reason", "cancelled_at"} |
created_at, updated_at | datetime |
Create a reservation
/properties/{property_id}/reservationsreservations:writeOperation reservation.createBooks a stay and returns it with 201 Created. Send the offer's total as expected_total, your own booking ID as external_ref, and an Idempotency-Key header.
Body
unit_id.room_type_id, it must be of that type. Without it, the hotel assigns a room later.rate_plan.id. Leave it out for the room type's own rate (rate_plan: null).YYYY-MM-DD.1.0.+14155550123.{"extra_id": uuid, "quantity": 1-99} (quantity defaults to 1). See extras.. _ : - /. Unique per partner and property: a second booking with the same value is refused.409 with the new total. Strongly recommended.| Header | |
|---|---|
Idempotency-Key | 1 to 255 characters. Strongly recommended: use one per booking attempt, for example your booking ID, and send the same key on every retry. See Idempotency |
Example
curl -X POST "https://api.chatbeds.app/partner/v1/properties/19306340-c7cf-465a-93d3-0b7873a7e85d/reservations" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: b2f1c9e4-booking-BK-104233" \
-d '{
"room_type_id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"external_ref": "BK-104233",
"notes": "Late arrival, around 23:00",
"expected_total": 180.0
}'{
"reservation": {
"id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"ref": "A589DF",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"status": "confirmed",
"source": "PARTNER:sandbox",
"external_ref": "BK-104233",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"nights": 2,
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"room_type": {
"id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"name": "Standard"
},
"unit": null,
"rate_plan": null,
"currency": "USD",
"total": 180.0,
"paid": 0.0,
"balance": 180.0,
"cancellation": null,
"created_at": "2026-10-10T05:09:47.271659+00:00",
"updated_at": "2026-10-10T05:09:47+00:00"
}
}Sending the same request again with the same Idempotency-Key returns the same 201 body with the header Idempotent-Replayed: true, and books nothing.
Errors
| Status | detail | What to do |
|---|---|---|
409 | The price has changed: the total is now USD 180.00. | Search offers again and show the guest the new price. Nothing was booked |
409 | A booking with external_ref BK-104233 already exists (a589df05-30ad-4ee5-9832-16ff6c2c1d0e). | This booking was already made: use the ID in the message, or reservation.search by external_ref |
409 | No Standard room is available for the selected dates. | Sold out since you searched. Search again |
409 | Unit is already booked for the selected dates. | The unit_id you chose is taken. Book by room type instead |
409 | Standard is not on sale. | The room type was switched off |
409 | A request with this Idempotency-Key is already being processed. | Two requests with the same key at once. Wait and retry with the same key |
400 | Give room_type_id (and unit_id to choose the room). | Neither was sent |
400 | That unit is not of that room type. | unit_id and room_type_id disagree |
400 | external_ref: letters, digits and . _ : - / only, up to 100 characters. | Fix the reference |
400 | Standard is closed to new bookings on ..., Stays arriving on ... need at least ... | The hotel's stay rules. Offers leave these out |
400 | That rate plan belongs to another property. | Wrong rate_plan_id |
400 | Idempotency-Key must be 1 to 255 characters. | |
404 | Room type not found, Unit not found, Extra not found, Property not found | An ID that is not this property's |
422 | A list of field problems | A required field is missing or out of range, or the Idempotency-Key was used for a different request |
{
"detail": [
{
"loc": [
"body",
"departure"
],
"msg": "Field required",
"type": "missing"
},
{
"loc": [
"body",
"guest"
],
"msg": "Field required",
"type": "missing"
}
]
}Get a reservation
/reservations/{reservation_id}reservations:readOperation reservation.getReturns one reservation at the property, whoever made it. Use it to refresh your copy when a webhook arrives.
Parameters
id.Example
curl -X GET "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e" \
-H "Authorization: Bearer cbk_••••"{
"reservation": {
"id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"ref": "A589DF",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"status": "confirmed",
"source": "PARTNER:sandbox",
"external_ref": "BK-104233",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"nights": 2,
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"room_type": {
"id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"name": "Standard"
},
"unit": null,
"rate_plan": null,
"currency": "USD",
"total": 180.0,
"paid": 0.0,
"balance": 180.0,
"cancellation": null,
"created_at": "2026-10-10T05:09:47.271659+00:00",
"updated_at": "2026-10-10T05:09:47+00:00"
}
}Errors
| Status | detail | When |
|---|---|---|
403 | The app token lacks reservations:read | |
404 | Reservation not found | No such reservation at this property |
Search reservations
/properties/{property_id}/reservationsreservations:readOperation reservation.searchFinds reservations at the property by exact arrival date, exact departure date, guest last name or your external_ref. Give at least one of those four; status and limit only narrow the result. Results are sorted by arrival, then by when they were made.
Parameters
last_name also works.confirmed, checked_in, checked_out, cancelled or no_show.50.Example
curl -X GET "https://api.chatbeds.app/partner/v1/properties/19306340-c7cf-465a-93d3-0b7873a7e85d/reservations?external_ref=BK-104233" \
-H "Authorization: Bearer cbk_••••"{
"reservations": [
{
"id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"ref": "A589DF",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"status": "confirmed",
"source": "PARTNER:sandbox",
"external_ref": "BK-104233",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"nights": 2,
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"room_type": {
"id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"name": "Standard"
},
"unit": null,
"rate_plan": null,
"currency": "USD",
"total": 180.0,
"paid": 0.0,
"balance": 180.0,
"cancellation": null,
"created_at": "2026-10-10T05:09:47.271659+00:00",
"updated_at": "2026-10-10T05:09:47+00:00"
}
]
}No ranges, no pages
arrival and departure match one date, not a range, and there is no next page. To cover a period, search day by day; if a day returns limit results, narrow it with status. See Keep bookings in sync.
Errors
| Status | detail | When |
|---|---|---|
400 | Search by arrival, departure, last_name or external_ref. | None of the four was given |
400 | Unknown status. Use confirmed, checked_in, checked_out, cancelled or no_show. | |
403 | The app token lacks reservations:read | |
404 | Property not found | |
422 | A date that is not a date, or limit out of range |
Modify a reservation
/reservations/{reservation_id}reservations:writeOperation reservation.modifyChanges the dates, the number of guests, the guest's details or the notes. Send only the fields that change. The room type and rate plan cannot change here: cancel and book again.
Body
first_name (1 to 100 characters), last_name (up to 100), email (up to 255), phone (up to 50). Fields you leave out are kept.How the price follows a change:
| Change | Effect on the folio |
|---|---|
| Nights kept | Keep the price they were booked at |
| New nights | Priced now, at today's rates |
| Nights dropped | Come off the folio |
| Extras sold per night | Follow the new number of nights |
| Extras sold per person | Follow the new number of guests |
| A booking with a price agreed by hand | Keeps its nightly rate for every night |
There is no expected_total check on a change: read the new total in the response and show it to the guest. The room (or, for a booking without a room yet, the room type) must be free on the new nights, and the rate plan's minimum stay still applies.
Example
curl -X PATCH "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-104233-change-1" \
-d '{
"adults": 2,
"notes": "Late arrival, around 23:30; needs a cot"
}'{
"reservation": {
"id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"ref": "A589DF",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"status": "confirmed",
"source": "PARTNER:sandbox",
"external_ref": "BK-104233",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"nights": 2,
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"room_type": {
"id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"name": "Standard"
},
"unit": null,
"rate_plan": null,
"currency": "USD",
"total": 180.0,
"paid": 0.0,
"balance": 180.0,
"cancellation": null,
"created_at": "2026-10-10T05:09:47.271659+00:00",
"updated_at": "2026-10-10T05:09:47+00:00"
}
}Notes are not part of the reservation object; the hotel sees them on the booking.
Errors
| Status | detail | When |
|---|---|---|
400 | Nothing to change. | The body had no field to change |
400 | Check-out date must be after check-in date. | |
400 | ... needs a stay of at least ... nights. ... | The new stay is shorter than the rate plan allows |
409 | A reservation with status 'cancelled' can only have its guest details and notes changed. | Dates or guests on a cancelled or checked-out booking |
409 | The guest has already arrived, so the arrival date cannot change. | The guest is checked in |
409 | No ... room is available for the selected dates., Unit is already booked for the selected dates. | The new nights are not free |
403 | The app token lacks reservations:write | |
404 | Reservation not found |
Cancel a reservation
/reservations/{reservation_id}/cancelreservations:writeOperation reservation.cancelCancels under the hotel's own cancellation policy. The fee the policy gives goes on the folio and the stay's charges come off; you cannot waive or change the fee. Payments already taken stay on the folio, so a negative balance is a refund the hotel owes the guest. The response includes the policy's explanation and the fee it charged.
Cancelling a reservation that is already cancelled changes nothing and answers with the reservation as it is, with policy: null. A no-show is also already cancelled.
Body
Example
curl -X POST "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/cancel" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-104233-cancel" \
-d '{"reason": "Guest changed plans"}'In this recorded run, a USD 100 payment had been recorded before cancelling. The sandbox hotel has no cancellation policy, so the fee is 0, the charges come off, and the USD 100 remains as a refund due (balance: -100.0).
{
"reservation": {
"id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"ref": "A589DF",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"status": "cancelled",
"source": "PARTNER:sandbox",
"external_ref": "BK-104233",
"arrival": "2026-10-31",
"departure": "2026-11-02",
"nights": 2,
"adults": 2,
"children": 0,
"guest": {
"first_name": "Daniel",
"last_name": "Moore",
"email": "daniel.moore@example.com",
"phone": "+14155550123"
},
"room_type": {
"id": "da3b4c87-c1ca-4f13-8c90-066900f16d48",
"name": "Standard"
},
"unit": null,
"rate_plan": null,
"currency": "USD",
"total": 0.0,
"paid": 100.0,
"balance": -100.0,
"cancellation": {
"fee": 0.0,
"reason": "Guest changed plans",
"cancelled_at": "2026-10-10T05:09:47.509902+00:00"
},
"created_at": "2026-10-10T05:09:47.271659+00:00",
"updated_at": "2026-10-10T05:09:47+00:00"
},
"policy": {
"explanation": "This hotel has no cancellation policy, so nothing is charged.",
"fee": 0.0
}
}Errors
| Status | detail | When |
|---|---|---|
409 | The guest is checked in. Check them out instead of cancelling. | |
409 | This stay is already finished and cannot be cancelled. | The guest has checked out |
403 | The app token lacks reservations:write | |
404 | Reservation not found |
Add an extra
/reservations/{reservation_id}/extrasreservations:writeOperation reservation.addExtraAdds an extra (breakfast, airport pick-up) to a confirmed or checked-in booking. It is priced for the booking's nights and guests by the extra's unit (per stay, per night, per person, per person per night), times quantity, and taxed like extras chosen at booking. It goes on the folio as its own line and the response is the updated reservation, with the new total and balance.
Body
extra.list.1.Example
curl -X POST "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/extras" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-104233-extra-breakfast" \
-d '{"extra_id": "<extra id from extra.list>", "quantity": 1}'The sandbox hotel has no extras, so there is no recorded response. The answer is 200 OK with {"reservation": {...}}, the same object as Get a reservation, its total and balance raised by the extra's amount (and tax). To see the extra's own line, read the folio.
Errors
| Status | detail | When |
|---|---|---|
409 | Extras cannot be added to a booking that is cancelled. (or checked out, no show) | Only confirmed and checked-in bookings take extras |
400 | ... is not on offer. | The hotel has switched the extra off |
403 | The app token lacks reservations:write | |
404 | Extra not found | Not an extra of this property |
404 | Reservation not found | |
422 | extra_id missing or not a UUID, quantity out of range |
Building something?
Availability
Search priced offers for a stay. Each offer is a room type on a rate plan, with the night-by-night price, fees, tax and the total to book at.
Folios and payments
Read a booking's bill, post charges, record payments you took, send a card payment link on the hotel's Stripe account, and check a payment's status.