Webhook 簽名驗證與冪等性
驗證原始 Webhook 主體,使用 HTTP 狀態碼進行確認,並可靠地處理重試和重複。
本頁依據 Agent Java SDK WEBHOOKS.md 提交 fa6c7b6 同步。此次僅更新文件,沒有發布包含預警輔助方法的新 SDK 製品。
四類事件共用一個商戶回呼 URL,依正文 event 分流。事件欄位與範例見 Webhook 事件與強平預警。
Webhook 標頭
事件冪等性
去重必須在商戶與 environment 範圍內持久化,並與業務處理原子提交。不同 notificationId 的 FIRST / UPGRADE / REMINDER 是獨立通知,不可依使用者、輪次或 eventType 合併丟棄。空冪等鍵不能用於去重。SDK 只回傳輔助鍵,不儲存或處理業務資料。同一身份、不同正文應記錄為衝突,不能覆蓋已處理的正文。
簽名驗證及接收
使用商家API秘密計算timestamp + nonce + rawBody的HMAC-SHA256十六進位簽章。驗證原始接收的位元組;不要先格式化 JSON、重新命名欄位或重新序列化正文。
先驗簽,再校驗時間視窗(建議 ±300 秒)、商戶與環境,然後提取冪等身份並可靠處理。保留未知事件原值供排查,不能視為資金成功。驗證輔助方法本身不執行時間、歸屬或持久去重校驗。
處理完成或確認同正文重複後回傳 HTTP 2xx;失敗回傳非 2xx。預警發送端 HTTP 逾時為 5 秒,最多 8 次嘗試。重試保持已凍結的正文,僅簽章時間與隨機數更新。可靠接管後儘快回應;耗時業務可使用商戶自己的持久任務。
商家通知不依賴使用者的線上狀態。平台用戶推播僅在線上盡力推送,無線下重播;第一階段沒有通知收件匣。
成功響應並停止重試
資金回呼和強平預警只根據 HTTP 狀態碼 判斷本次投遞結果,不解析回應正文的 code、success、result 或 message,也不要求固定回傳 OK / success。
回應正文可為空、文字或 JSON。範例 result 欄位僅供商戶閱讀,不是協定要求。202 Accepted 同樣會停止平台重試,因此必須先將通知可靠保存到商戶自己的持久任務佇列,不能只啟動記憶體非同步任務就確認成功。
成功響應範例
業務處理完成後,或通知已可靠地儲存至商家本身的待處理佇列:
當不需要響應體時:
對於已經處理過且body相同的通知,跳過重複的業務處理,仍然返回2xx:
失敗回應範例
例如資料庫暫時不可用,商戶尚未完成處理,也未可靠保存通知,應回傳非 2xx,讓平台後續重試:
拒絕無效簽名而不更新業務資料或成功的重複資料刪除記錄:
這些回應正文不影響重試判斷。不能期待回傳 401 或 409 就永久停止重試;需要排查簽章、通知內容或商戶設定。
錯誤範例:以下回應仍會被平台視為投遞成功,不會因 success:false 而觸發重試。
如果框架或統一例外處理預設將業務錯誤包裝成 HTTP 200,回呼入口須明確設定正確的 HTTP 失敗狀態。
可靠的確認和重複傳送
建議順序:驗證簽章並檢查時間/商家/環境→提取冪等性身分→處理事務中的業務資料和成功去重記錄,或可靠保存待處理任務→提交成功後回傳200/204。在成功寫入資料庫之前,不要返回 2xx 或將通知標記為已處理。
商戶處理成功後仍可能收到重複請求:回應可能在網路中遺失,或平台收到 2xx 後未能持久化 SUCCESS。HTTP 回呼不保證只投遞一次。必須在商戶與 environment 範圍內持久去重。資金使用 orderType:orderId:targetStatus,預警使用 liquidation.warning:notificationId。已處理的同正文通知回傳 2xx,避免重複入帳或提醒;同一身份、不同正文應記錄衝突並回傳非 2xx,不能覆蓋原記錄。
確認成功是指商家收到/處理了通知,而不是資金作業成功。以targetStatus=FAILED記錄有效資金通知後,也回2xx;訂單失敗並非拒絕通知確認的理由。
資金和環境邊界
原始合約轉帳 webhook 和 queryOrder 流程不會自動應用於資金。使用queryWalletTransfer和原始訂單環境確認資金操作。資金用途status;原始合約傳輸回應使用orderStatus。成功的 HTTP 回應或 code=0 本身並不能證明資金已轉移。
明確模擬合約轉移通知包括environment=SIMULATED。首先驗證原始主體,然後根據已儲存的本地業務訂單檢查使用者、金額、訂單身分和環境。