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.
Every reservation has a folio: the guest's bill. Room nights, extras, fees and tax go on it as charges when the booking is made; payments go on it as they are received. balance is what is still owed.
Bookings made through the API are pay at the hotel. If your app takes the money, record it with folio.addPayment; if the hotel should take it by card, send the guest a payment link. The Take payments guide walks through both.
Get the folio
/reservations/{reservation_id}/foliofolios:readOperation folio.getReturns every line on the bill (voided lines included and marked), the totals, the balance and the payments.
Parameters
Example
curl -X GET "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/folio" \
-H "Authorization: Bearer cbk_••••"{
"folio": {
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"currency": "USD",
"lines": [
{
"id": "bdaead22-6697-49a1-ad00-510f88b151cc",
"type": "ROOM_CHARGE",
"description": "Standard, night of 2026-10-31",
"amount": 90.0,
"service_date": "2026-10-31",
"posted_at": "2026-10-10T05:09:47.274835",
"voided": false,
"void_reason": null,
"payment_id": null
},
{
"id": "7df0796f-3e3e-48ff-8361-eeeff715f7b4",
"type": "ROOM_CHARGE",
"description": "Standard, night of 2026-11-01",
"amount": 90.0,
"service_date": "2026-11-01",
"posted_at": "2026-10-10T05:09:47.277372",
"voided": false,
"void_reason": null,
"payment_id": null
},
{
"id": "442f2691-f69f-4da3-bfc6-de650d9a9866",
"type": "INCIDENTAL",
"description": "Airport transfer",
"amount": 35.0,
"service_date": "2026-10-10",
"posted_at": "2026-10-10T05:09:47.387569",
"voided": false,
"void_reason": null,
"payment_id": null
},
{
"id": "d3dc1f18-4b15-42b5-bf9f-a3b375b3435e",
"type": "PAYMENT",
"description": "Paid through Sandbox key",
"amount": 100.0,
"service_date": null,
"posted_at": "2026-10-10T05:09:47.406626",
"voided": false,
"void_reason": null,
"payment_id": "763300e8-3898-4fba-a0b0-0a0cc86ba611"
}
],
"total_charges": 215.0,
"total_payments": 100.0,
"balance": 115.0,
"payments": [
{
"id": "763300e8-3898-4fba-a0b0-0a0cc86ba611",
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"kind": "PAYMENT",
"amount": 100.0,
"currency": "USD",
"method": "CARD",
"status": "COMPLETED",
"reference": "BK-PAY-88231",
"paid_at": "2026-10-10T05:09:47.406608+00:00",
"created_at": "2026-10-10T05:09:47.405620+00:00",
"url": null,
"expires_at": null
}
]
}
}| Field | Meaning |
|---|---|
lines[].type | ROOM_CHARGE (one per night), INCIDENTAL (extras and charges), FEE, TAX, PAYMENT, REFUND |
lines[].service_date | The night or day the charge is for; null for payments |
lines[].voided | true when the hotel took the line off the bill; void_reason says why. Voided lines do not count in the totals |
lines[].payment_id | On PAYMENT and REFUND lines, the payment it records |
total_charges | All charges not voided |
total_payments | Payments received, less refunds |
balance | total_charges minus total_payments. Negative means the hotel owes the guest money |
payments[] | Every payment, including links not yet paid |
Errors
| Status | detail | When |
|---|---|---|
403 | The app token lacks folios:read | |
404 | Reservation not found |
Add a charge
/reservations/{reservation_id}/folio/chargesfolios:writeOperation folio.addChargePuts something the guest had on the bill: a transfer, a meal, a tour you sold. The line is amount times quantity, dated today at the hotel, and tax is recalculated. Returns the whole folio.
Body
Airport transfer.1. Above 1 the line reads Airport transfer x2.Example
curl -X POST "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/folio/charges" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-104233-charge-transfer" \
-d '{"description": "Airport transfer", "amount": 35, "quantity": 1}'{
"folio": {
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"currency": "USD",
"lines": [
{
"id": "bdaead22-6697-49a1-ad00-510f88b151cc",
"type": "ROOM_CHARGE",
"description": "Standard, night of 2026-10-31",
"amount": 90.0,
"service_date": "2026-10-31",
"posted_at": "2026-10-10T05:09:47.274835",
"voided": false,
"void_reason": null,
"payment_id": null
},
// ... the night of 2026-11-01
{
"id": "442f2691-f69f-4da3-bfc6-de650d9a9866",
"type": "INCIDENTAL",
"description": "Airport transfer",
"amount": 35.0,
"service_date": "2026-10-10",
"posted_at": "2026-10-10T05:09:47.387569",
"voided": false,
"void_reason": null,
"payment_id": null
}
],
"total_charges": 215.0,
"total_payments": 0.0,
"balance": 215.0,
"payments": []
}
}Errors
| Status | detail | When |
|---|---|---|
409 | A cancelled booking takes no new charges. | |
409 | The stay is over: the hotel adds any late charge itself. | The guest has checked out |
403 | The app token lacks folios:write | |
404 | Reservation not found | |
422 | description empty or over 120 characters, amount not above 0, quantity out of range |
Record a payment
/reservations/{reservation_id}/folio/paymentsfolios:writeOperation folio.addPaymentRecords money you took for the hotel (on your own payment gateway, say), so the bill shows it paid. ChatBeds does not move any money here. You can record at most what is owed. Returns the payment and the updated folio.
Body
balance.CASH, CARD or BANK_TRANSFER.Example
curl -X POST "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/folio/payments" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-PAY-88231" \
-d '{"amount": 100, "method": "CARD", "reference": "BK-PAY-88231"}'{
"payment": {
"id": "763300e8-3898-4fba-a0b0-0a0cc86ba611",
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"kind": "PAYMENT",
"amount": 100.0,
"currency": "USD",
"method": "CARD",
"status": "COMPLETED",
"reference": "BK-PAY-88231",
"paid_at": "2026-10-10T05:09:47.406608+00:00",
"created_at": "2026-10-10T05:09:47.405620+00:00",
"url": null,
"expires_at": null
},
"folio": {
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"currency": "USD",
"lines": [
// ... the two nights and the airport transfer, as above
{
"id": "d3dc1f18-4b15-42b5-bf9f-a3b375b3435e",
"type": "PAYMENT",
"description": "Paid through Sandbox key",
"amount": 100.0,
"service_date": null,
"posted_at": "2026-10-10T05:09:47.406626",
"voided": false,
"void_reason": null,
"payment_id": "763300e8-3898-4fba-a0b0-0a0cc86ba611"
}
],
"total_charges": 215.0,
"total_payments": 100.0,
"balance": 115.0,
"payments": [
{
"id": "763300e8-3898-4fba-a0b0-0a0cc86ba611",
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"kind": "PAYMENT",
"amount": 100.0,
"currency": "USD",
"method": "CARD",
"status": "COMPLETED",
"reference": "BK-PAY-88231",
"paid_at": "2026-10-10T05:09:47.406608+00:00",
"created_at": "2026-10-10T05:09:47.405620+00:00",
"url": null,
"expires_at": null
}
]
}
}The payment line reads "Paid through" and your key's or app's name, so the hotel knows where the money is.
Errors
| Status | detail | When |
|---|---|---|
400 | Only USD 115.00 is owed on this booking. | amount is more than the balance |
403 | The app token lacks folios:write | |
404 | Reservation not found | |
422 | amount not above 0, or method not one of the three |
Create a payment link
/reservations/{reservation_id}/payment-linkpayments:writeOperation payment.createLinkMakes a Stripe Checkout page on the hotel's own Stripe account for the guest to pay by card. The money goes to the hotel; ChatBeds marks the payment completed when Stripe confirms it. The link stays open for 23 hours. Send the returned url to the guest.
It works only when the hotel has connected Stripe: check features.payment_links in GET /capabilities.
Body
Example
curl -X POST "https://api.chatbeds.app/partner/v1/reservations/a589df05-30ad-4ee5-9832-16ff6c2c1d0e/payment-link" \
-H "Authorization: Bearer cbk_••••" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: BK-104233-link-1" \
-d '{}'The sandbox hotel has no Stripe account connected, so the recorded call answers 400:
{
"detail": "Card payments are not set up for this hotel. An owner connects Stripe on the Finance page."
}With Stripe connected, the answer is 200 OK with {"payment": {...}}: a payment with method: "STRIPE", status: "PENDING", the Checkout page in url and its expires_at. Poll payment.getStatus to see when it is paid.
Errors
| Status | detail | When |
|---|---|---|
400 | Card payments are not set up for this hotel. An owner connects Stripe on the Finance page. | No Stripe. Do not offer card payment for this hotel |
400 | Nothing is owed on this booking. | No amount and the balance is 0 |
400 | A card payment link for ... is already open for what is owed. | A link for the whole balance is still open. Use it, or wait for it to expire |
400 | Only ... is owed on this booking (... more is on a card link still open). | amount is more than is owed |
402 | The hotel's plan does not include card payments | |
409 | This booking is cancelled. | |
502 | Stripe could not be reached. Try again in a moment., Stripe did not accept the hotel's key. ..., or Stripe: ... with Stripe's message | Stripe refused or did not answer. No link was made; retry later, or tell the hotel if its key was refused |
403 | The app token lacks payments:write | |
404 | Reservation not found |
Get a payment
/payments/{payment_id}folios:readOperation payment.getStatusReturns one payment at the property: one you recorded, a payment link, or a payment taken at the front desk.
Parameters
id, from a payment link, a recorded payment or the folio.Example
curl -X GET "https://api.chatbeds.app/partner/v1/payments/763300e8-3898-4fba-a0b0-0a0cc86ba611" \
-H "Authorization: Bearer cbk_••••"{
"payment": {
"id": "763300e8-3898-4fba-a0b0-0a0cc86ba611",
"reservation_id": "a589df05-30ad-4ee5-9832-16ff6c2c1d0e",
"kind": "PAYMENT",
"amount": 100.0,
"currency": "USD",
"method": "CARD",
"status": "COMPLETED",
"reference": "BK-PAY-88231",
"paid_at": "2026-10-10T05:09:47.406608+00:00",
"created_at": "2026-10-10T05:09:47.405620+00:00",
"url": null,
"expires_at": null
}
}The payment object
| Field | Meaning |
|---|---|
kind | PAYMENT or REFUND |
method | CASH, CARD, BANK_TRANSFER, or STRIPE for a payment link |
status | See below |
reference | The reference you or the hotel gave. Always null for STRIPE |
paid_at | When it was paid; set only when COMPLETED |
url | The Checkout page; set only while PENDING |
expires_at | When a payment link closes |
| Status | Meaning |
|---|---|
PENDING | A payment link not paid yet. url is the page to send |
COMPLETED | Paid. Counts on the folio |
EXPIRED | A payment link nobody paid before expires_at. Create a new one |
VOIDED | Entered by mistake and taken off the folio by the hotel |
FAILED | The payment did not go through |
Errors
| Status | detail | When |
|---|---|---|
403 | The app token lacks folios:read | |
404 | Payment not found | Not a payment at this property |
Building something?