Webhooks
瞭解 StableOps Webhook 的事件模型、HMAC 簽名驗證、自動重試、併發限制、死信佇列與安全重放機制,並透過事件去重避免重複履約或重複記帳。掌握端點設定、金鑰輪換、投遞狀態與故障恢復方法,讓支付、訂閱和運維事件能夠可靠進入業務系統。
Webhook 讓你的應用在 StableOps 中發生事件(例如支付被檢測、確認、最終化)時即時收到通知。
總覽
不必輪詢 API 查支付狀態,事件發生時 StableOps 會直接 HTTP POST 到你的服務。好處:
- 即時:到帳立刻知道。
- 節省呼叫:不必持續輪詢。
- 可靠投遞:失敗自動指數退避重試。
- 可回放:所有投遞都有日誌,可在 dashboard 重放。
工作流
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 區塊鏈 │────────▶│ StableOps │────────▶│ 你的應用 │
└─────────────┘ └─────────────┘ └─────────────┘
支付發出 檢測到事件 派發 Webhook- 某個事件發生(例如鏈上檢測到支付)
- StableOps 建立一條 Webhook 投遞
- 向你的端點發 HTTP POST
- 你的服務處理後返回 200 OK
- 投遞失敗則指數退避重試
Webhook 事件
支付相關事件
payment_order.created
新訂單建立時傳送。
payment.detected
掃描器首次看到對應轉帳時傳送。掃描可能落後於鏈頭,此時不一定恰好是 0 確認。
動作:把 UI 切換到「支付已收到,確認中…」。
注意:此時不要履約,交易仍有可能被回滾。
payment.confirmed
支付獲得足夠鏈上確認時傳送。交易基本不可能回滾,但尚未達到鏈的 finality 保證。
動作:可以更新內部系統並通知使用者,但建議等待 payment.finalized 後再發貨。
payment.finalized
支付達到 finality、不再可回滾時傳送。
動作:可以安全履約。資金已經穩定。
這是推薦用來觸發履約的事件。
payment.expired
訂單超過過期時間仍未匹配到任何轉帳時傳送。
動作:把訂單標記為過期,引導使用者重新下單。
payment.reverted
已檢測到的支付被回滾時傳送。receipt 執行失敗,或區塊在重組後 block hash 不再與儲存的事件匹配。
動作:撤銷任何基於 payment.detected / payment.confirmed 做的樂觀處理。這也是
建議等 payment.finalized 再履約的原因。
payment_order.canceled
仍處於 created(尚未檢測到任何入帳)的訂單被呼叫 cancel 取消時傳送。
動作:把訂單標記為已取消,釋放任何為它預留的資源。
注意:雖然取消由使用者主動觸發、HTTP 回應已經返回結果,仍會回推此事件。這樣以 webhook 流為唯一事實源(event sourcing)的接入方不會漏掉這次終態流轉。不關心的接入方 可以直接忽略它。
完整 payload 結構請參見 Payment Events API 參考。
商家訂閱事件
StableOps 也會為商戶管理的終端使用者訂閱和訂閱帳單推送事件。你可以用這些事件開通帳號、跟蹤續費、暫停逾期使用者,並對帳帳單支付結果。
| 事件 | 觸發時機 |
|---|---|
end_user_subscription.created | 商家訂閱建立 |
end_user_subscription.activated | 首期帳單已支付,訂閱變為 active |
end_user_subscription.renewed | 續費帳單已支付,帳期向前推進 |
end_user_subscription.canceled | 訂閱被立即取消 |
end_user_subscription.expired | 訂閱因期末取消或未付款而過期 |
end_user_subscription.past_due | 訂閱進入 past_due 狀態 |
end_user_invoice.open | 新的訂閱帳單已開出 |
end_user_invoice.paid | 訂閱帳單已支付 |
end_user_invoice.payment_failed | 訂閱帳單支付失敗 |
end_user_invoice.payment_late | 帳單已判為不可收回後又收到付款 |
訂閱帳單 Checkout 底層仍會建立付款單,因此你也可能收到該底層付款單的普通支付事件。訂閱狀態請以
end_user_invoice.* 和 end_user_subscription.* 事件為準。
各事件完整 payload 結構請參見 Subscription Events API 參考。
運維與 Agent 事件
除支付事件外,StableOps 還會在以下場景推送事件。在控制台裡它們構成運維事件訂閱分組。一個開關覆蓋全部,與支付事件分組相互獨立:
| 事件 | 觸發時機 |
|---|---|
address.pool.low | 某條鏈的可用收款地址池低於水位線 |
agent.action.requested | Agent 發起一個需要審批的寫操作 |
agent.action.approved | 待審批的 Agent 操作被批准 |
agent.action.executed | 已批准的 Agent 操作完成執行 |
各事件完整 payload 結構請參見 Operational Events API 參考。
接入 Webhook
1. 建立端點
在 StableOps dashboard:
- 進入 Webhooks(左側導覽欄)
- 點 Add Endpoint
- 填入你的 Webhook URL(生產環境建議使用 HTTPS)
- 勾選訂閱的事件型別
- 儲存 Webhook secret
secret 欄位只在建立與 rotate 時返回一次,Dashboard 不會再展示,請安全儲存。
呼叫 rotate-secret 後,舊 secret 仍保留 24 小時與新 secret 同時有效,便於
你平滑地把驗籤 key 切換到新值,不會丟投遞。
2. 驗證簽名
始終驗證簽名,確保請求來自 StableOps。
import { SIGNATURE_HEADER, verifySignature } from '@stableops/api-sdk/webhooks'
const result = verifySignature({
secrets: [webhookSecret],
header: request.headers.get(SIGNATURE_HEADER) ?? undefined,
rawBody,
})
if (!result.ok) {
console.error('Invalid signature:', result.reason)
// 拒絕請求
}投遞、重試與死信
成功判定
任何 2xx 回應都算成功。其它狀態碼、網路錯誤、或者超過 10 秒 沒返回,都按
失敗處理。
重試退避
失敗後按下表延遲重排,第 6 次仍失敗轉入 DLQ(dead letter queue):
| 第幾次 | 間隔 |
|---|---|
| 1 | 30 秒 |
| 2 | 60 秒 |
| 3 | 5 分鐘 |
| 4 | 30 分鐘 |
| 5 | 2 小時 |
| 6+ | DLQ |
投遞記錄欄位
webhook-deliveries 上你能查到的關鍵欄位:
| 欄位 | 說明 |
|---|---|
attempts | HTTP 已嘗試的次數 |
response_status | 最近一次下游返回的狀態碼 |
response_duration_ms | 最近一次耗時 |
error_message | 最近一次失敗的簡短原因 |
next_retry_at | 下次重試時間;進入終態時為 null |
status | pending / succeeded / failed / dead_letter |
Replay
三個重放介面(endpoint replay、單條 delivery replay、批次 replay dead letters) 都是建立一條 delivery 記錄進行投遞,原審計日誌保持不變。Dashboard 的 "replay" 按鈕就是呼叫這些介面。
最佳實踐
1. 始終驗證簽名
拒絕任何不帶有效 X-Product-Signature 的請求。不驗籤的話,只要別人知道你的端點 URL 就能偽造事件。
2. 儘快返回 200
驗籤並記錄 X-Event-Id 後立即返回 200。履約、通知、帳本更新等耗時操作應非同步處理,否則投遞超時會觸發無謂的重試。
3. 按 X-Event-Id 冪等處理
在變更自身狀態前先記錄 X-Event-Id。網路重試和平台重放可能多次投遞同一事件,重複執行必須安全。
4. 驗籤必須用 raw body
簽名計算的是收到的原始位元組,任何 JSON 解析或重新序列化都會改變 body 內容、破壞簽名。務必在驗簽完成後才解析 JSON。
5. 處理全部相關事件型別
訂閱並妥善處理你可能收到的每種事件,包括 payment.reverted、payment.expired,以及
end_user_invoice.paid / end_user_subscription.renewed 等訂閱事件。未處理的事件雖然也算投遞成功,但你的訂單和訂閱狀態會逐漸失準。
6. 詳盡記錄日誌
記錄每次投遞的 X-Event-Id、X-Delivery-Id、事件型別以及你的處理結果。完善的日誌是排查漏單或重複履約最快的手段。
7. 監控投遞健康度
定期檢查投遞日誌,留意 failed 或 dead_letter 數量上升的端點。對過去一小時未返回 2xx 的端點設定告警,問題修復後用 replay 介面清空死信佇列。
下一步
這篇文件怎麼樣?
最後更新