Meta (Instagram, Facebook, Threads) 如何傳遞 Webhook

Meta 會在 36 小時內以遞減的頻率重試,之後丟棄事件。附 hub.challenge 交握、簽章格式與 Node 驗證程式。

傳遞行為

取自服務商自己的文件,最後檢查於 2026-08-06。服務商沒寫數字的地方,這張表也不填。

回應時限服務商未公開
重試36 小時內以遞減的頻率重試,之後丟棄。WhatsApp Cloud API 最多重試 7 天
放棄服務商未公開
出處https://developers.facebook.com/docs/graph-api/webhooks/getting-started

簽章

用一個經測試套件證明可運作的驗證程式核對過,不是照文件抄來的。最後驗證於 2026-08-20。

演算法HMAC-SHA256
簽章內容raw body
編碼hex
標頭x-hub-signature-256 = sha256=hex
容許時間差不強制

驗證簽章

要用原始請求主體(raw body),逐位元組原封不動,並在任何 JSON 解析之前取得。框架只要重新序列化 payload,這頁上的每一種機制就會立刻失效。

const crypto = require("node:crypto");

// Same scheme as GitHub: "sha256=" + hex HMAC of the raw body, keyed by the
// app secret.
const expected =
  "sha256=" +
  crypto.createHmac("sha256", appSecret).update(rawBody).digest("hex");
const received = Buffer.from(req.headers["x-hub-signature-256"] ?? "");
const wanted = Buffer.from(expected);
// timingSafeEqual throws on a length mismatch, so check that first.
const valid =
  received.length === wanted.length && crypto.timingSafeEqual(received, wanted);

這些步驟執行之前,Meta 必須先接受回呼網址(Callback URL):它會送出一個帶 hub.mode=subscribe 的 GET,並要求原封不動地回傳 hub.challenge。沒有回傳,就沒有訂閱。

容易踩的坑

Meta 公布了重試期間(36 小時、頻率遞減,之後丟棄通知),但沒有公布單一請求的回應時限或停用門檻。服務商沒寫數字的地方,這頁也不寫。

延伸閱讀

AnyHook 架在接收 Meta Webhook 的端點前面:大約 1 秒就回應,伺服器當機時依自己的排程重試,並讓每個事件都能重播。 換一個網址,程式碼不用動。

運作方式 →