跳至內容
開發者資源整合 Webhook

整合 Webhook

要開始在你的應用程式中接收 webhook 事件,請按照以下步驟創建並註冊 webhook URL 端點:

  1. 創建 webhook 端點處理器 來接收事件數據的 POST 請求。
  2. 使用後台 註冊你的端點。
  3. 保護你的 webhook 端點。
  4. 使用測試付款 測試你的 webhook 端點。

1. 創建處理器

設置一個能夠通過 POST 方法接受 webhook 請求的 HTTPS 端點功能。你可以使用 Webhook.site 來查看有效酬載和測試傳送。

確保你的端點功能:

• 處理帶有 JSON 酬載的 POST 請求,該酬載包含一個事件物件。 • 在執行可能導致超時的複雜邏輯之前,快速返回成功的狀態碼(2xx)。

2. 註冊你的端點

在 Tokenz Dashboard 上註冊你的 webhook 端點。

  1. 前往你的 主頁。
  2. 點擊 創建新 webhook。
  3. 填寫你的 URL 和可選的描述,並選擇你希望接收的事件。我們建議至少選擇 order.succeeded 以確保不會錯過成功的客戶訂單。
  4. 點擊 創建 webhook。
  5. 複製並保存返回的簽名金鑰。你需要它來驗證收到的 webhook。基於安全性考量,我們只會顯示一次金鑰。

3. 保護你的 webhook 端點

Tokenz 發送的所有 webhook 都包含簽名,你必須驗證這個簽名以確保 webhook 是由 Tokenz 發送並且沒有被篡改。或者,你可以將 webhook 通知僅作為觸發器,通過 API 檢查訂單狀態變更。我們建議驗證 webhook 簽名以避免不必要的 API 請求。

每個簽名的事件都包含一個 Tokenz-Signature header,其中包含時間戳 (t:<unix-timestamp-in-milliseconds>) 和一個或多個版本簽名 (v1:<HMAC signature>) 需要驗證。目前有效的簽名方案是 v1。

Example:

plaintext
t:1725864981111,v1:zjdrra3...Mh+e6s=

驗證簽名

1. 提取時間戳和簽名

使用逗號(,)作為分隔符拆分 header 以創建元素列表。然後使用冒號(:)作為分隔符拆分每個元素以得出 前綴 和 值,前綴 t 代表時間戳,而 v1 包含簽名,其他元素則忽略。

2. 準備用於簽名的有效酬載

將時間戳(作為字串)與請求主體(即 JSON 酬載)的原始文本直接連接起來,組成有效酬載字符串。

3. 計算簽名

使用 SHA256 雜湊函數計算 HMAC。使用端點的簽名金鑰作為金鑰,將有效酬載字符串作為雜湊計算時的訊息本文。

4. 比較簽名

將 HTTP header 中的簽名與預期簽名進行匹配。評估當前時間與接收時間戳之間的差異以防止重放攻擊。如果簽名有效但時間戳已過期,應用程序可以拒絕有效酬載。建議的容許誤差為 300 秒(5 分鐘)。

重放攻擊發生在攻擊者攔截並重新傳輸合法的有效酬載及其簽名時。Tokenz 通過在 Tokenz-Signature header 中包含時間戳來減輕這種攻擊。

javascript
const crypto = require('crypto');
const express = require('express');
const app = express();
const port = 3000;

// Use express.raw() so the signature is computed over the exact bytes
// Tokenz sent; re-serializing a parsed body can fail verification.
// If your app registers express.json() or another body parser globally,
// mount this webhook route BEFORE it so the raw body is preserved.
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  // The signing secret shown once on webhook creation is Base64-encoded.
  const secret = 'webhook-endpoint-secret';
  const sig = req.headers['tokenz-signature'];

  let timestamp, signature;
  for (let sigPart of sig.split(',')) {
    let [key, value] = sigPart.split(':');

    if (key === 't') {
      timestamp = value;
    } else if (key === 'v1') {
      signature = value;
    }
  }

  const checkSignature = crypto.createHmac('sha256', Buffer.from(secret, 'base64'))
    .update(`${timestamp}${req.body.toString('utf8')}`)
    .digest('base64');

  // The `t` value in Tokenz-Signature is a Unix timestamp in milliseconds.
  const tolerance = 5 * 60 * 1000; // 5 minutes

  if (
    signature === checkSignature &&
    Math.abs(Date.now() - Number(timestamp)) <= tolerance
  ) {
    return res.status(200).end();
  } else {
    return res.status(400).end();
  }
});

4. 測試你的 webhook 端點

為了確保你的 webhook 處理正確運行,請按照我們的測試指南創建並完成一些測試付款。