Skip to Content
Webhook總覽
View as Markdown

Webhook 總覽

Webhook 是權威訊號。瀏覽器回呼 (onSuccess) 與儀表板畫面僅是 輔助資訊;Webhook 才是真相之源。

投遞保證

  • 至少一次。 若你的伺服器未在逾時內回應 2xx,單一事件最多會被 投遞 6 次。處理函式請保持冪等 — 以 X-Delivery 去重。
  • 每個 HTTP 請求僅一個事件。 不做批次。
  • 每個端點獨立。 如果你註冊了多個端點,各自擁有獨立的投遞與 重試軌道。某個慢的端點不會拖累其他端點。
  • 已簽章。 每個酬載都帶 X-Signature 標頭(於密鑰輪替後的 24 小時 視窗期內,還會附帶 X-Signature-Prev)。處理 body 前請先驗證。 詳見簽章驗證。

可訂閱的事件類型

事件觸發條件
payment.settled鏈上轉帳達到該鏈的確認數。用此事件標記訂單為已付款。
payment.failed法幣付款被支付 provider 拒絕。不會因為加密貨幣超時而觸發 — 那些情境會以 checkout.expired 呈現;而短付的加密貨幣付款會以 payment.underpaid 呈現。
payment.underpaid資金已抵達但不足訂單總額(典型範例:穩定幣轉帳手續費從金額中扣除)。
payment.overpaid資金超過訂單總額。多出的部分被記錄,但不會自動退款。
order.created新訂單建立 — 透過你的 B2B API 呼叫或結帳會話轉換。
order.canceled訂單轉為取消。酬載中的 data.reason 區分手動取消與 payment_timeout(未付款訂單逾時)。
order.resolved一個 PARTIAL_PAID 訂單被解析為 PAID — 商家接受短缺。
order.reopened先前自動取消(canceled_reason=payment_timeout)的訂單被商家重新開啟。
checkout.created買家開啟了訂單的結帳。
checkout.completed買家端流程完成(不代表鏈上結算 — 那是 payment.settled 的事)。
checkout.expired買家放棄,會話 TTL 已過。
payment.refund.requested退款紀錄被建立 — 來自商家發起的 API 呼叫,或客戶提交的退款申請表單。
payment.refund.approved待審退款通過你的核准流程。
payment.refund.rejected待審退款被駁回。
payment.refund.executed退款的鏈上轉帳已確認,紀錄進入終態 executed。
refund_request.createdRefund-request token 被鑄造。data.source 為 b2b / dashboard / renewal。訂閱與否為選擇性 — 對於追蹤每個訂單目前哪個 token 是有效的稽核管線很有用。
refund_request.renewal_requested買家在 token 過期後點了「申請新連結」。強烈建議訂閱 — 這是商家收到續期 widget 有新項目需要處理的訊號。
refund_request.renewed續期通過核准,新的 token 取代舊的。data.old_token / data.new_token 形成稽核鏈。
refund_request.canceled商家從儀表板把一個 token 翻為 CANCELED(例如駁回續期請求、終止仍有效的連結)。冪等 — 只有第一次轉換會發出。data.reason 是商家選填的備註。

規劃中(Coming soon)

即將推出。 這些事件屬於定期帳單與訂閱功能,目前尚未提供。 它們不在上方可訂閱的表格中,目前無法訂閱。請見 定期帳單。

規劃中的事件觸發時機…
subscription.created建立訂閱時。
invoice.created建立某個計費週期的帳單時。
invoice.paid帳單已付款時。
subscription.past_due帳單逾期未付時。
subscription.canceled訂閱被取消時。

儀表板的端點表單列出相同的事件。訂閱不存在的事件會在你儲存端點時 被拒絕。

測試事件無法訂閱。 儀表板上的逐端點 Send Test 按鈕會立即把一個 webhook.test.ping 事件送到該端點,不會重試。它不在上面的目錄中: 你是因為註冊了端點才會收到它,而不是因為訂閱。

只訂閱你會處理的事件。每個端點有獨立的事件過濾器;萬用字元 "*" 代表「所有事件,包含未來新增的」。訂閱較少事件可讓處理函式更簡單, 也能在你的端點出錯時減少重試。

酬載 + 標頭

HTTP body 直接是事件專屬的 data 物件。沒有 Stripe 風格的外層 信封 — 事件類型、投遞 ID、發出時間等欄位改放在標頭裡。對於 payment.settled,body 看起來像這樣:

{ "receipt_id": "rcp_…", "order_id": "ord_…", "payment_intent_id": "pin_…", "checkout_session_id": "cst_…", "merchant_id": "mer_…", "customer_id": "cus_…", "total": "49.00", "currency": "USD", "payment_method": "crypto", "token": "USDC", "network": "polygon", "tx_hash": "0x…", "deposit_address": "0x…", "treasury_address": "0x…", "amount_received": "49.00", "confirmations": 5, "metadata": { /* 每事件 */ } }

其他事件帶各自的欄位。 欄位名稱穩定(lower snake_case);鏈上交易雜湊永遠是 tx_hash。

tx_hash 是該網路自有格式的交易識別碼(EVM 鏈上為 0x…;TRON、Solana、TON 上為原生雜湊或簽章)。對於 TRON、Solana 與 TON,買家直接付款到你的資金庫錢包,因此 deposit_address 可能不存在;confirmations 依照支援的鏈與資產。

入站請求的標頭

Content-Type: application/json X-Event: payment.settled X-Delivery: 7c9e6679-7425-40de-944b-e07fc1f90ae7 Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7 X-Timestamp: 1729536000 X-Signature: sha256=9a8b7c… X-Signature-Prev: sha256=fa31b2… (僅在輪替寬限視窗期內出現)
標頭內容
X-Event事件類型(例如 payment.settled)。如想跳過 JSON 解析,可在代理層以此路由。
X-DeliveryUUID,識別一筆投遞列。在同一 (event, endpoint) pair 的所有重試間穩定 — 請以它作為冪等鍵。
Idempotency-Key與 X-Delivery 對應(同值)。每次投遞都會帶。
X-Timestamp嘗試送出時的 Unix 秒。簽入酬載,使被捕獲的 (body, X-Signature) 對無法被無限重放 — 對超出容差視窗的投遞請拒絕。
X-SignatureHMAC-SHA256(secret, X-Timestamp + "." + raw_body) 的 sha256=<hex>。詳見簽章驗證。
X-Signature-Prev相同演算法但使用前一個金鑰。僅在輪替後的 24 小時視窗期內出現 — 讓使用任一金鑰的驗證器在切換期間都能繼續接受投遞。視窗關閉後此標頭便不再發送。

重試時程

若你的端點未在逾時內回應 2xx,我們依下列時程重試(時間戳相對首次 嘗試):

嘗試延遲累計
10s0s
2+1 分1m
3+5 分6m
4+15 分21m
5+1 小時1h 21m
6+6 小時7h 21m

第 6 次嘗試失敗後,投遞會標示為 Failed,你的帳號信箱會收到 通知。你可以從儀表板的 Developers → Webhooks → Delivery history 面板重放失敗的事件。每次重放都是一筆新的投遞,擁有自己的 X-Delivery。

註冊端點

在商家儀表板 中:

  1. Developers → Webhooks → + Add endpoint
  2. 貼上你的 URL — 僅限 https://…(純 HTTP 會被拒絕;建立表單也會 阻擋 localhost、私有 IP 範圍、以及攜帶使用者資訊的 URL)
  3. 選擇要訂閱的事件(或 * 代表全部)
  4. 選擇環境 — test 或 live(各自擁有獨立金鑰,二者永不交叉)
  5. 儲存 → 儀表板僅顯示一次簽章金鑰(whsec_…)。請保存到伺服端; 下面兩個功能會用到它。

每個商家每個環境最多可註冊 10 個端點(例如:一個用於正式履約, 一個用於預備鏡像,一個用於 Slack 通知)。每個端點有獨立的重試 狀態與金鑰。

每個端點的生命週期操作

每張端點卡片的 ⋮ 選單提供:

  • Edit — 變更 URL、描述或訂閱列表。新 URL 會以與建立時相同的 https:///SSRF 規則重新驗證。
  • Send Test — 以你目前的金鑰同步 POST 一個 webhook.test.ping 信封。儀表板顯示 HTTP 狀態、延遲與你回應的前 512 位元組。測試 ping 不會重試, 因此能立即得到結果。
  • Rotate Secret — 產生新金鑰。前一個金鑰仍維持 24 小時 有效 (期間投遞同時帶 X-Signature 與 X-Signature-Prev,讓使用任一 金鑰的驗證器在你重新部署期間都能繼續接受事件)。
  • Reveal Secret — 重新顯示目前金鑰。受新的 2FA 驗證控管並記錄 到稽核日誌;僅在你遺失副本且無法接受輪替時使用。
  • Enable / Disable — 不遺失投遞歷史的情況下開啟或關閉端點。 停用的端點仍保留在儀表板,但不再接收新投遞。
  • Delete — 永久刪除。若可能再次啟用,請使用 Disable。

處理函式小技巧

  1. 儘速回應 2xx。 在做重活前先以 200 OK 確認 — 把履約移到 背景作業。每次嘗試的逾時為 10 秒;回應保持超過此時間會觸發 重試。此逾時為平台端設定,商家無法調整 — 若你的 handler 確實 需要更多時間,請聯絡 support。
  2. 以 X-Delivery 去重(或同值的 Idempotency-Key)。即使你 回應了 2xx,上游代理可能斷線並觸發重試;投遞 ID 在同一筆投遞 列的每次重試之間穩定,因此是正確的鍵。
  3. 容忍未知事件類型。 可能會出現新事件;請回 200 + no-op, 而非 4xx,否則這些投遞會持續重試。
  4. 在業務邏輯旁邊記錄 X-Delivery。 出問題時,這就是我們這邊 與你那邊的串接鍵。

下一步