IOSOR 知識庫

重複的 Webhook 絕不能導致二次扣款

失敗路徑:重試與重放必須在預付資金與收件匣中保持冪等性——單一事件 ID、單一扣款列、單一收件匣記錄。

「至少一次」傳遞機制必然會觸發重試。若一個「重複的 Webhook」導致了第二次扣款或產生了第二條收件匣記錄,這屬於嚴重的資金與營運事故,而非「無害的確認」。本頁面專注於「失敗路徑」:重試與重放必須在預付資金與收件匣中保持冪等性,這與 API 的發送冪等性論文或入站 SMS 重試策略不同。

相關連結:簽章與重放時窗閘道、首次發送前的 Webhook 契約、同一帳本上的扣款列與送達狀態。

IOSOR 是白標預付系統。USD 20 的資金足以驗證單一消費者發生重複事件時的煙霧測試;而接近 USD 1,000/月的軟性審查則將「重試等於新收費」視為對帳債務。客戶僅能看見白標事件 ID。

冪等性是失敗路徑,而非口號

成功路徑:一個已簽章事件、一次接受、一次扣款。失敗路徑則會損害信任——超時、5xx 錯誤、供應商重放、營運商重新推送。請在執行副作用(帳本、收件匣、CRM)之前,儲存來自 首次發送前的 Webhook 契約 的冪等性金鑰。USD 1,000/月的軟性標準將「先確認再發明新金鑰」視為流量債務;USD 20 則證明了強制重放絕不會導致資金翻倍。

什麼算作重複

訊號 判定重複的條件 安全結果
事件 ID 同一 ID 已在時窗內被接受 確認;無二次扣款
訊息 ID 同一訊息已連結至帳本 重用列;無新收費
收件匣金鑰 同一 MO/MT 已歸檔 無第二條記錄
超出時窗 閘道拒絕後的陳舊重試 拒絕;無資金寫入

簽章與重放時窗閘道 負責判斷真實性與時效性。本頁面負責處理「有效重複事件」發生後的狀態:單一終局、單一資金列、單一收件匣記錄。

資金絕不能移動兩次

即使產品介面「顯示已送達」,針對同一事件 ID 進行第二次扣款仍是錯誤。財務部門透過事件或訊息 ID 過濾時,應僅看到該 UTC 時窗內的一筆預付列。在確認後發生部分副作用(例如先更新 CRM,後更新帳本)會製造虛假的雙重紀錄。若持久化後處理失敗,請使用相同金鑰重試工作,切勿將 HTTP 本體視為新收費重新接受。在重複測試顯示「單一帳本列」之前,軟性流量指標將保持封鎖。

收件匣也不得重複

冪等性不僅關乎資金。重放的入站或送達事件若開啟了第二個收件匣執行緒,會導致支援團隊疲於奔命,並可能觸發自動回覆迴圈。請使用與扣款相同的事件 ID 儲存收件匣金鑰。產品與財務部門應共享拒絕/重複的術語:產品與財務的共用狀態語言。USD 20 證明了強制重放不會改變收件匣的基數。

重複安全型 Webhook 的買家檢查清單

  1. 冪等性金鑰格式是否已在契約中約定,並在副作用發生前儲存?
  2. 時窗內的重複事件 ID 是否在「無二次扣款」的情況下完成確認?
  3. 同一訊息 ID 是否從未開啟第二個預付帳本列?
  4. 收件匣插入是否使用相同金鑰,確保重放時不會產生第二個執行緒?
  5. 簽章失敗與時窗拒絕是否與真實重複事件分開統計?
  6. 在重複測試呈現紅色時,是否已封鎖 USD 1,000/月的軟性談判?

任何「否」的回答都會讓重複安全型 Webhook 的資金與收件匣信任度停留在草稿階段。

從 IOSOR 開始

在已經入帳的通道上,於重放時窗內強制再送一則已簽章的 webhook。把事件 id 與 ledger id 並列匯出,只准看到一列扣款與一列收件。若冒出第二筆扣款,立刻停掉該消費者並退回多寫的列,不准用後面流量去沖銷。這是重放金流閘,不是電話格式檢查,也不是出貨簡訊口吻。

IOSOR 要點

重放不是新的一封。一個事件 id 只准寫一筆扣款。

該做:簽章與時窗開著,時窗內 POST 後只核一筆扣款。別做:每張 POST 都扣,或把網路重試當成第二張發票。

這篇指南有幫助嗎?

相關指南