Webhook 整合
Webhook 讓您的系統在 Wink 帳戶發生事件時接收即時通知 — 新訂單、取消、付款更新等。此指南將引導您完成設定及最佳實踐。
本指南適用於將 Wink 與外部系統整合的開發人員,例如物業管理系統(PMS)、渠道管理器、CRM 或自訂儀表板。
Webhook 運作方式
Section titled “Webhook 運作方式”- 您在 Wink 上註冊 webhook URL。
- 當事件發生(例如新訂單),Wink 會向您的 URL 發送 HTTP POST。
- 您的伺服器處理負載並回應
200 OK。
設定 webhook
Section titled “設定 webhook”- 登入您的帳戶(Extranet、Studio 或 TripPay — 均支援 webhook)。
- 前往
Applications,然後點選Webhooks。詳見 Webhooks。 - 點擊
Create webhook。 - 輸入 名稱(例如「PMS 訂單同步」)。
- 輸入您的 webhook URL — 您伺服器上的 HTTPS 端點。
- 選擇事件 — 選擇要訂閱的特定事件,或留空以接收所有事件。
- 切換 Enabled 為開啟。
- 點擊
Save— 回應會顯示您的 簽署密鑰(signing secret)一次;請立即妥善保存。
Wink 目前發布 70 種 webhook 事件類型,涵蓋訂單、物業、帳戶(管理實體)及庫存(房型、價格方案、主價格、附加項目、設施、銷售渠道、促銷活動)。常見類型:
| 類別 | 範例 |
|---|---|
| 訂單 | booking.create、booking.cancelled、booking.refund.partial、booking.refund.full、booking.review.created |
| 物業 | property.created、property.status.updated、property.policy.updated |
| 庫存 | room_type.updated、rate_plan.created、master_rate.updated、special_rate.created、sales_channel.created |
| 帳戶 | managing_entity.created、managing_entity.status.updated、managing_entity.manager.added |
完整且自動生成的清單 — 含描述、接收對象及每個事件參考頁面連結 — 即為 Webhook 事件目錄。每個事件的參考頁面(JSON 主體、標頭、重試政策)位於 Webhooks API。
查看所有事件類型
您會收到什麼
Section titled “您會收到什麼”每次傳送都是 HTTP POST 到您的 webhook URL,Content-Type: application/json,格式如下:
{ "id": "0198a4f2-6b0e-7c1d-9a3e-2f4b8c6d1e0a", "type": "booking.create", "occurredAt": "2026-08-15T09:30:00Z", "ownerIdentifier": "3c6b1a5d-8e2f-4a0b-9c7d-6e4f0a8b2c51", "recipientRole": "SUPPLIER", "schemaVersion": 2, "object": { "...": "event-specific payload, e.g. BookingWebhookPayload" }}id— 事件識別碼;對您帳戶接收此事件的每個端點及每次重試皆相同。用作您的 冪等鍵。type— 事件類型鍵(同時作為Wink-Event-Type標頭)。根據type和schemaVersion解析object。object— 事件所關聯資源的精選摘要(識別碼、狀態、您操作的欄位)及links.self,供應商端完整資源的標準 REST URL。需要完整資料時,使用您自己的 API 憑證抓取;若您是轉售商或旅行社,請使用您 API 介面中相同識別碼的對應資源端點。
每個負載結構於 Webhooks API 參考中依事件記錄。
| 標頭 | 含義 |
|---|---|
Wink-Version | 通訊協定版本,2.0。 |
Wink-Event-Id | 與主體中 id 相同 — 您的冪等鍵。 |
Wink-Delivery-Id | 每個端點每事件唯一;僅在重新傳送時變更。 |
Wink-Event-Type | 與主體中 type 相同。 |
Wink-Delivery-Attempt | 此次傳送的嘗試次數(從 1 開始)。 |
Wink-Signature | HMAC 簽章 — 詳見下方。 |
每個 webhook 有一組 簽署密鑰(whsec_…),Wink 在您建立 webhook 或輪替密鑰時只顯示 一次。請妥善保存,視同密碼。每次傳送都帶有:
Wink-Signature: t=1755250200,v1=5d41402abc4b2a76b9719d911017c592…其中 t 是 Unix 時間戳(秒),v1 是以您的密鑰為鍵,對字串 t + "." + rawBody 計算的十六進位小寫 HMAC-SHA256,rawBody 是收到的原始請求主體位元組 — 驗證前請勿重新序列化 JSON。密鑰輪替後 24 小時內,標頭會帶有第二個用舊密鑰簽署的 v1= 值;只要 任一 v1 符合即接受傳送。
驗證流程四步驟:解析 t 與所有 v1;用密鑰重新計算 t.rawBody 的 HMAC;以常數時間比較;若 |now − t| 超過容忍時間(建議 5 分鐘)則拒絕。
// Node.js (Express-style; 確保取得 RAW 主體,而非解析後物件)import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWinkSignature(header, rawBody, secret, toleranceSeconds = 300) { const parts = Object.fromEntries(header.split(',').map((p) => p.split('=').map((s) => s.trim()))); const t = Number(parts.t); if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return header .split(',') .filter((p) => p.trim().startsWith('v1=')) .map((p) => p.trim().slice(3)) .some((v1) => v1.length === expected.length && timingSafeEqual(Buffer.from(v1, 'utf8'), Buffer.from(expected, 'utf8')));}// Javastatic boolean verify(String header, String rawBody, String secret, long nowSeconds, long toleranceSeconds) throws Exception { long t = Long.MIN_VALUE; List<String> signatures = new ArrayList<>(); for (String part : header.split(",")) { String[] kv = part.trim().split("=", 2); if (kv[0].equals("t")) t = Long.parseLong(kv[1]); else if (kv[0].equals("v1")) signatures.add(kv[1]); } if (t == Long.MIN_VALUE || Math.abs(nowSeconds - t) > toleranceSeconds) return false; Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] expected = HexFormat.of().formatHex(mac.doFinal((t + "." + rawBody).getBytes(StandardCharsets.UTF_8))).getBytes(StandardCharsets.US_ASCII); return signatures.stream().anyMatch(v1 -> MessageDigest.isEqual(expected, v1.toLowerCase().getBytes(StandardCharsets.US_ASCII)));}您可從入口網站或使用 POST /api/managing-entity/{id}/webhook/{webhookId}/rotate-secret 輪替密鑰;回應會顯示新密鑰一次,舊密鑰在您部署期間的 24 小時內仍可驗證。
重試與重新傳送
Section titled “重試與重新傳送”- 請在 10 秒內以任何
2xx回應確認接收。繁重工作請非同步處理。 5xx、逾時、408或429會依序延遲重試:1 分鐘、5 分鐘、30 分鐘、2 小時、6 小時、12 小時,然後每日一次 — 共 10 次嘗試,約 3 天後標記為 失效。- 其他
4xx視為「您拒絕此傳送」,不會重試。 - 每個事件、傳送與嘗試(狀態、回應摘要)皆可於 Applications > Webhooks 及 API (
…/webhook/event/grid、…/webhook/delivery/grid) 查看。您可 重新傳送 任一傳送(POST …/webhook/delivery/{deliveryId}/redeliver,啟動新重試序列)、一次重新傳送 webhook 所有失效傳送(POST …/webhook/{webhookId}/redeliver-dead),或取消傳送。 - 傳送紀錄保留 30 天。
您可從入口網站或使用 POST /api/managing-entity/{id}/webhook/{webhookId}/test 傳送合成的 webhook.test 事件。此事件簽署並傳送方式與真實事件相同,方便您驗證端點、簽章檢查及冪等處理,確保訂閱正式事件前一切正常。
- 使用 HTTPS — Wink 僅傳送負載至 HTTPS 端點。
- 快速回應 — 收到負載後立即回傳
200 OK。繁重處理請非同步執行。 - 冪等性 — 處理程序應具冪等性;以
Wink-Event-Id去重。Wink 未收到2xx回應會重試。 - 驗證來源 — 處理前驗證
Wink-Signature標頭(參見 驗證簽章);驗證失敗即拒絕。 - 記錄 — 記錄每個收到的 webhook 負載,有助於除錯整合問題。
您可以 停用 webhook 而不刪除。這會暫停傳送,方便您排查問題且不會遺失設定。準備好後可切回啟用。
刪除 webhook 則會永久移除。任何依賴該 webhook 的整合將停止接收通知。
- Webhook 事件目錄 — 平台目錄自動生成的所有事件類型。
- Webhooks API 參考 — 各事件負載結構、標頭及訂閱/傳送管理端點。
- Webhooks — webhook 管理完整參考。
- Applications — 管理您的 API 憑證。
- Developers > APIs — 完整 API 文件。
