Webhook: nhận sự kiện đặt phòng
Bạn vẫn đọc được đầy đủ hướng dẫn bên dưới. Khi cần bật, nhắn Zalo OA GoHost — CS sẽ giúp trong 1 ngày làm việc.
Webhook gửi POST tới URL HTTPS của bạn khi một đặt phòng của cơ sở được tạo, sửa, huỷ, nhận hoặc trả phòng
— kể cả đơn do lễ tân hay kênh OTA tạo, không chỉ đơn tạo qua API. Bạn quản lý webhook bằng chính API, theo từng cơ sở, với scope
webhooks:read / webhooks:write (key cũ chưa có hai scope này — xin GoHost thêm).
Sự kiện
Phần tiêu đề “Sự kiện”| Sự kiện | Khi nào |
|---|---|
booking.created | Đặt phòng mới |
booking.updated | Đặt phòng bị sửa (không gửi khi cùng thao tác đã có một sự kiện bên dưới) |
booking.confirmed | Đơn được xác nhận qua API (Confirm Booking); xác nhận trên GoHost đến dưới dạng booking.updated |
booking.cancelled | Đơn bị huỷ |
booking.checked_in | Khách nhận phòng |
booking.checked_out | Khách trả phòng |
webhook.ping | Gửi thử bằng endpoint Ping — không đăng ký được |
1. Đăng ký endpoint
Phần tiêu đề “1. Đăng ký endpoint”curl -s -X POST "$GOHOST_API/properties/<tenant_id>/webhooks" \ -H "Authorization: Bearer $GOHOST_KEY" -H "Content-Type: application/json" \ -d '{ "url": "https://partner.example.com/gohost/webhook", "events": ["booking.created", "booking.cancelled"] }'Phản hồi có secret dạng whsec_… — chỉ hiện một lần, lưu lại để kiểm chữ ký. Body đầy đủ:
Store Webhook Endpoint.
Ràng buộc: URL phải là https (cổng 443), không chứa user:pass, không trỏ vào địa chỉ mạng nội bộ; GoHost
không theo redirect (3xx tính là thất bại). Mỗi key, trên mỗi cơ sở: tối đa 5 endpoint đang bật, mỗi URL
đăng ký một lần.
Gửi thử: Ping → nhận sự kiện webhook.ping.
2. Nội dung mỗi lần gửi
Phần tiêu đề “2. Nội dung mỗi lần gửi”{ "id": "evt_01j…", "type": "booking.created", "created_at": "2026-11-20T14:05:09+07:00", "tenant_id": "<tenant_id>", "data": { "id": "…", "…": "…" }}datacó cùng cấu trúc với Get Booking Detail.created_attheo múi giờ của cơ sở.idkhác nhau cho từng endpoint. Dùng nó để bỏ qua sự kiện trùng — cùng một sự kiện có thể tới nhiều lần khi GoHost gửi lại.
Header đi kèm: X-Gohost-Signature, X-Gohost-Event-Id, X-Gohost-Event, X-Gohost-Timestamp,
User-Agent: GoHost-Webhook/1.0.
3. Kiểm chữ ký
Phần tiêu đề “3. Kiểm chữ ký”X-Gohost-Signature có dạng t=<unix timestamp>,v1=<chữ ký>, trong đó chữ ký là
HMAC-SHA256 (hex) của chuỗi "<t>.<raw body>" với khoá là secret của endpoint.
- Tách
tvàv1từ header. - Tính HMAC-SHA256 của
t + "." + body gốc(đúng byte nhận được, chưa parse JSON). - So sánh với
v1bằng hàm so sánh an toàn thời gian. - Từ chối nếu
tlệch giờ máy bạn quá 5 phút (chống gửi lại).
// Node.js — Express: dùng express.raw({ type: 'application/json' }) để giữ nguyên bodyimport crypto from 'node:crypto';
function verifyGohostSignature(rawBody, header, secret) { const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('='))); const t = Number(parts.t); if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); const a = Buffer.from(expected); const b = Buffer.from(parts.v1 ?? ''); return a.length === b.length && crypto.timingSafeEqual(a, b);}// PHPfunction verifyGohostSignature(string $rawBody, string $header, string $secret): bool { parse_str(str_replace(',', '&', $header), $p); $t = (int) ($p['t'] ?? 0); if ($t === 0 || abs(time() - $t) > 300) return false; $expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret); return hash_equals($expected, $p['v1'] ?? '');}Đổi secret: Rotate Secret — secret cũ mất hiệu lực ngay, cập nhật bên bạn trước khi gọi.
4. Trả lời và gửi lại
Phần tiêu đề “4. Trả lời và gửi lại”- Trả mã 2xx trong 5 giây là thành công. Xử lý nặng thì đưa vào hàng đợi rồi trả 200 ngay.
- Không thành công: ngoài lần gửi đầu, GoHost gửi lại tối đa 8 lần, cách nhau 5 giây, 30 giây, 2 phút, 10 phút, 30 phút, 2 giờ, 6 giờ, 24 giờ (tổng 9 lần thử).
- Trả
410 Gone: endpoint bị tắt ngay. 8 sự kiện liên tiếp đều thất bại hết 9 lần thử: endpoint tự tắt — bật lại bằng Update Webhook Endpoint (is_active: true). - Xem lịch sử gửi (giữ 14 ngày): Deliveries.
- API key bị tắt thì mọi webhook của key đó cũng tắt theo và không bật lại được.
Hỗ trợ trực tiếp 8:00–22:00 hằng ngày, kể cả cuối tuần.