Developers · for developers
Webhooks
Receive signed real-time events — bookings, check-ins, payments, unlocked stays, extras and guest messages — and verify the HMAC-SHA256 signature.
Webhooks push events to your system the moment they happen, so you don't need to poll the API.
Events #
| Event | When |
|---|---|
booking.created | A booking was created (dashboard, channel import or API) |
booking.updated | Dates, guests or contact details changed |
booking.cancelled | A booking was cancelled |
checkin.completed | The guest completed (or updated) the online check-in |
payment.completed | Tourist tax paid or deposit held/paid |
booking.unlocked | All steps are done — the stay guide is unlocked |
extras.ordered | The guest paid for extras |
message.sent | A message was sent to the guest through the booking channel (Airbnb, Booking.com … via Hostaway or Channex) |
ping | Test event from the Test button |
Add a webhook #
Settings → Webhooks: enter an https:// URL, tick the events you want (none = all) and click Add webhook. The signing secret is shown once — store it with your receiver.
The request #
POST with a JSON body:
{
"id": "evt_…",
"event": "payment.completed",
"createdAt": "2026-11-18T14:03:11.000Z",
"tenant": "t_…",
"data": { "bookingId": "b_…", "leg": "eco", "status": "paid" }
}
Headers:
| Header | Content |
|---|---|
X-GP-Event | the event name |
X-GP-Delivery | unique delivery ID |
X-GP-Timestamp | Unix time in seconds |
X-GP-Signature | v1= + hex HMAC-SHA256 of <timestamp>.<raw body> with your signing secret |
Verify the signature (Node.js) #
const crypto = require('crypto');
function verify(rawBody, headers, secret) {
const ts = headers['x-gp-timestamp'];
const expected = 'v1=' + crypto.createHmac('sha256', secret).update(ts + '.' + rawBody).digest('hex');
const given = String(headers['x-gp-signature'] || '');
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && given.length === expected.length && crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
Always verify against the raw request body, and reject old timestamps to block replays.
Delivery and retries #
Answer with any 2xx status within 10 seconds. Failed deliveries are retried after 30 seconds and after 5 minutes. Recent deliveries shows the last 200 attempts with their result. Use id to ignore duplicates.
Frequently asked questions #
Do I get the full booking in the event? #
The event carries IDs and the change. Fetch the full booking with GET /api/v1/bookings/{id} using an API key — that way no personal data travels in webhook bodies.
Are webhooks sent from the demo account? #
No.
