Webhooks
Get a signed POST whenever a booking at a connected property is made, changed or cancelled, from anywhere.
Instead of polling, let ChatBeds tell you when bookings change. Whenever a booking at a property is made, changed or cancelled, ChatBeds sends a signed POST to your webhook address with the whole booking.
Events fire for changes from anywhere: the dashboard, WhatsApp, another partner, or your own API calls.
Setting the address
| You use | Where to set it |
|---|---|
| An app | Developers → your app → Webhook. One address and one whsec_ secret for every connection. Only connections that allowed reservations:read get events |
| A private key | Settings → Partner API, on the key. Each key has its own address and secret |
The address must be https and on the public internet. The secret is shown once when you save; saving again makes a new one.
Events
| Event | Fires when |
|---|---|
reservation.created | A booking is made |
reservation.modified | A booking's dates, guests or details change, it moves to another room, a room is assigned, or the guest checks in or out |
reservation.cancelled | A booking is cancelled, or marked a no-show |
GET /capabilities lists the events under features.webhooks. A no-show arrives as reservation.cancelled with "status": "no_show" in the reservation, so check the status rather than the event name alone.
The request
POST /chatbeds/webhooks HTTP/1.1
Content-Type: application/json
User-Agent: ChatBeds-Webhooks/1
ChatBeds-Event: reservation.created
ChatBeds-Delivery: c8839bfe-aa2f-4ac4-9847-d30e112516d6
ChatBeds-Signature: t=1791608987,v1=6900418cbb9ac7a69603cc6751a85d6abad4b93767052291f909c243aff58bc6{
"id": "c8839bfe-aa2f-4ac4-9847-d30e112516d6",
"type": "reservation.created",
"created_at": "2026-10-10T05:09:47.298146+00:00",
"property_id": "19306340-c7cf-465a-93d3-0b7873a7e85d",
"data": {
"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"
}
},
"triggered_by": "partner"
}The body is sent compact (no spaces); it's shown formatted here.
| Field | Meaning |
|---|---|
id | The delivery's ID. Same as the ChatBeds-Delivery header, and the same on every retry |
type | The event, as in ChatBeds-Event |
created_at | When the event happened |
property_id | The property. With an app, use it to find the connection |
data.reservation | The booking, in the same shape as GET /reservations/{id}, as it was when the event happened |
triggered_by | partner when the change came through the partner API (from any partner, including you), hotel otherwise |
A cancellation carries the policy's outcome:
{
"status": "cancelled",
"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"
}
}Headers
| Header | Value |
|---|---|
ChatBeds-Event | reservation.created, reservation.modified or reservation.cancelled |
ChatBeds-Delivery | The delivery ID. Use it to ignore repeats |
ChatBeds-Signature | t=<unix time>,v1=<hex HMAC-SHA256>. See Verify signatures |
User-Agent | ChatBeds-Webhooks/1 |
Answering
Answer any 2xx status within 10 seconds. Anything else, a redirect, or no answer counts as a failure and is retried. See Retries and delivery.
Nothing your server does can hold up or undo a booking: the change has already happened when you hear about it.
Building something?