跳到內容

Webhook 整合

Webhook 讓您的系統在 Wink 帳戶發生事件時接收即時通知 — 新訂單、取消、付款更新等。此指南將引導您完成設定及最佳實踐。

本指南適用於將 Wink 與外部系統整合的開發人員,例如物業管理系統(PMS)、渠道管理器、CRM 或自訂儀表板。

  1. 您在 Wink 上註冊 webhook URL。
  2. 當事件發生(例如新訂單),Wink 會向您的 URL 發送 HTTP POST。
  3. 您的伺服器處理負載並回應 200 OK
  1. 登入您的帳戶(Extranet、Studio 或 TripPay — 均支援 webhook)。
  2. 前往 Applications,然後點選 Webhooks。詳見 Webhooks
  3. 點擊 Create webhook
  4. 輸入 名稱(例如「PMS 訂單同步」)。
  5. 輸入您的 webhook URL — 您伺服器上的 HTTPS 端點。
  6. 選擇事件 — 選擇要訂閱的特定事件,或留空以接收所有事件。
  7. 切換 Enabled 為開啟。
  8. 點擊 Save — 回應會顯示您的 簽署密鑰(signing secret)一次;請立即妥善保存。

Wink 目前發布 70 種 webhook 事件類型,涵蓋訂單、物業、帳戶(管理實體)及庫存(房型、價格方案、主價格、附加項目、設施、銷售渠道、促銷活動)。常見類型:

類別範例
訂單booking.createbooking.cancelledbooking.refund.partialbooking.refund.fullbooking.review.created
物業property.createdproperty.status.updatedproperty.policy.updated
庫存room_type.updatedrate_plan.createdmaster_rate.updatedspecial_rate.createdsales_channel.created
帳戶managing_entity.createdmanaging_entity.status.updatedmanaging_entity.manager.added

完整且自動生成的清單 — 含描述、接收對象及每個事件參考頁面連結 — 即為 Webhook 事件目錄。每個事件的參考頁面(JSON 主體、標頭、重試政策)位於 Webhooks API

查看所有事件類型

每次傳送都是 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 標頭)。根據 typeschemaVersion 解析 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-SignatureHMAC 簽章 — 詳見下方。

每個 webhook 有一組 簽署密鑰whsec_…),Wink 在您建立 webhook 或輪替密鑰時只顯示 一次。請妥善保存,視同密碼。每次傳送都帶有:

Wink-Signature: t=1755250200,v1=5d41402abc4b2a76b9719d911017c592…

其中 t 是 Unix 時間戳(秒),v1 是以您的密鑰為鍵,對字串 t + "." + rawBody 計算的十六進位小寫 HMAC-SHA256rawBody 是收到的原始請求主體位元組 — 驗證前請勿重新序列化 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')));
}
// Java
static 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 小時內仍可驗證。

  • 請在 10 秒內以任何 2xx 回應確認接收。繁重工作請非同步處理。
  • 5xx、逾時、408429 會依序延遲重試: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 的整合將停止接收通知。