什麼是 Webhook?App 如何互相通知
Webhook 是某項服務在某件事發生時,自動傳送到你 App 的訊息。當客戶的付款成功時,Stripe 會把一則 Webhook 送到你 App 中的某個位址,說明「付款成功,以下是詳細資料」,然後你的 App 就會做出反應:將訂單標記為已付款、寄出收據、解鎖帳號。簡單來說:API 是你的 App 向另一項服務提出問題;Webhook 則是另一項服務呼叫你的 App,告訴它發生了什麼事。
用 AI 建站時,為什麼它很重要
一旦你的 App 開始收款、接收來自其他工具的表單提交,或連接 GitHub、Shopify 或行事曆等服務,你就會遇到 Webhook。它們通常是得知某件事已發生的正確方式,但也是 AI 建置的 App 最常見出錯的地方:
- 端點會接受任何請求,因此任何人都可以偽造「付款成功」事件。
- App 在結帳跳轉頁面上就授予存取權限,而不是在 Webhook 上授權。結果是提早關閉分頁的人付了錢卻拿不到內容,而找到成功頁網址的人則能免費取得。
- 同一個事件送達兩次,客戶因此收到兩筆訂單或兩封郵件。
了解 Webhook 的運作方式,讓你能在一開始就要求必要的保護。
日常生活的比喻:送貨簡訊
你可以用兩種方式知道包裹是否已送達。你可以每十分鐘走到前門查看(這叫做輪詢(polling):你的 App 反覆呼叫 API 詢問「有新的東西嗎?」)。或者快遞員在送達後傳一則簡訊給你(這就是 Webhook)。
簡訊顯然比較好,前提是你能信任它。如果任何人都能傳「包裹已送達」的訊息給你,你會希望有辦法確認它真的來自快遞公司。而且如果簡訊來的時候你的手機沒開機,你會希望快遞公司稍後再試一次。這兩個問題(驗證與重試)正是 Webhook 難處理的大部分原因。
Webhook 的運作方式,一步一步來
- 你在 App 的後端建立一個端點。 也就是接受
POST請求的網址,例如https://yourapp.com/webhooks/stripe。 - 你把該網址向服務商登記,並選擇要接收哪些事件(例如「結帳完成」和「訂閱取消」)。
- 服務商會提供一組簽章密鑰。 你要把它當作機密資料儲存在伺服器上,請參閱環境變數與機密資料。
- 事件發生。 服務商會向你的網址發出 HTTP 請求,內容是描述該事件的 JSON,並附上簽章標頭。
- 你的 App 驗證簽章,記錄事件 ID,快速回傳成功代碼(
200),然後才開始處理工作。 - 如果你的 App 沒有回傳成功,許多服務商會稍後再試。
簽章
簽章可以證明請求確實來自服務商,且內容沒有被竄改。例如 Stripe 會使用簽章密鑰,對請求內容與時間戳記計算 HMAC(一種帶密鑰的指紋,演算法為 SHA-256),並放在 Stripe-Signature 標頭中傳送。你的 App 用自己持有的密鑰做相同的計算;若結果相符,就表示請求是真實的。由於時間戳記也經過簽章,你可以拒絕別人先前記錄下來、之後重播的舊請求。根據 Stripe 截至 2026 年 9 月的文件,其函式庫預設的容忍時間為五分鐘。
一個實務細節:簽章是根據**原始(raw)**請求內容計算的。如果你的框架在驗證前就解析並重新排列了 JSON,檢查就會失敗。這是非常常見的錯誤。
重試、重複與順序
各服務商的做法不同,請自行查閱其文件。截至 2026 年 9 月:
| 行為 | Stripe | GitHub |
|---|---|---|
| 自動重試 | 有,正式模式下最多三天,間隔逐漸拉長 | 沒有;你需要手動或透過腳本重新傳送失敗的傳遞 |
| 回應時間 | 盡快回傳 2xx,在任何耗時工作之前 | 超過 10 秒才回應的傳遞會被視為失敗 |
Stripe 的文件也說明,事件不保證會按照發生的順序抵達,而且同一個事件偶爾可能送達不止一次,因此建議記錄事件 ID。
這個一般原則適用於任何服務商:事件可能延遲抵達、重複抵達,也可能亂序抵達。你的處理程式應具備冪等性(idempotent),也就是處理同一個事件兩次,與只處理一次的效果相同。
實例:解鎖付費課程
你販售一門線上課程。學員按下購買,在 Stripe 的託管結帳頁面付款,然後被導回你的網站。
脆弱的做法: 「感謝」頁面解鎖課程。如果學員在跳轉途中關閉瀏覽器,他們已付款卻沒有存取權限。如果有人猜到感謝頁的網址,他們不用付款就能取得存取權限。
使用 Webhook 的做法:
- Stripe 確認付款後,會把
checkout.session.completed事件送到/webhooks/stripe。 - 你的後端使用簽章密鑰驗證簽章。如果驗證失敗,就回傳
400,且不做任何事。 - 它檢查這個事件 ID 是否已經處理過。如果是,就回傳
200並停止。 - 它儲存事件 ID,回傳
200,然後授予學員存取權限並寄出歡迎郵件。 - 感謝頁面只顯示「已收到付款,您的課程即將出現」,並檢查學員的存取狀態。
之後,如果訂閱被取消或信用卡扣款失敗,其他 Webhook 事件會通知你的 App 移除或暫停存取權限。這就是訂閱型產品如何與帳單保持同步的方式,請參閱什麼是 SaaS與如何為你的 App 加入付款功能。
關鍵名詞
- 端點(Endpoint): 你 App 中接收 Webhook 的網址。
- 事件/酬載(Event/payload): 發生了什麼事,以及描述它的資料(通常是 JSON)。
- 簽章密鑰(Signing secret): 用來驗證簽章的共享密鑰。
- 冪等性(Idempotent): 以相同的輸入重複執行,結果仍然相同,因此重複執行是安全的。
- 輪詢(Polling): 反覆向 API 詢問是否有變化,而不是等待 Webhook。
- 通道(Tunnel): 一種工具,可以為你的筆電提供暫時的公開網址,讓開發期間 Webhook 能送達。
常見錯誤與迷思
- 沒有驗證簽章。 端點網址並不是秘密。驗證才是讓請求變得可信的關鍵。
- 在回應之前做耗時工作。 在回應之前寄信或產生 PDF,可能造成逾時,逾時會觸發重試,重試又造成重複。
- 假設恰好一次、按順序抵達。 記錄事件 ID,不要依賴抵達的順序。
- 使用預覽網址。 Webhook 需要穩定的公開位址。私人預覽與
localhost無法從網際網路存取;請使用你已發布的網址(或在測試時使用通道)。 - 混用測試與正式密鑰。 服務商通常會為測試模式與正式模式分別發行不同的簽章密鑰。兩組都要儲存,並使用正確的那一組。
- 對重要決策盲目信任酬載。 對於高風險的動作,在收到事件後,向服務商的 API 取得最新狀態是合理的做法。
向你的 AI 建置工具要求什麼
在伺服器上新增一個
POST /webhooks/stripe端點。使用原始請求內容與密鑰STRIPE_WEBHOOK_SECRET驗證 Stripe 簽章。簽章無效時以 400 拒絕。儲存每個事件 ID,並略過已處理過的事件。快速回傳 200,然後處理checkout.session.completed:將訂單標記為已付款並寄出收據。記錄事件類型。不要在結帳成功頁面授予存取權限。
接著測試它:從服務商的後台傳送一個測試事件,再傳送同一個事件一次,並送出一個簽章錯誤的請求。只有第一次應該改變任何資料。
Mythex 中的 Webhook
Mythex 沒有獨立的 Webhook 服務;你請 Agent 在 App 自己的後端新增 Webhook 端點,並把服務商指向你已發布的網址,因為 Webhook 需要公開位址。簽章密鑰放進專案的機密設定中,若要在正式 App 上更換密鑰,就需要重新發布。文件中的處理 Webhook範例包含起始提示詞,而商店範本則是接受付款的 App 很好的起點。
常見問題
用白話來說,什麼是 Webhook?
Webhook 是某項服務在某件事發生時(例如付款成功或表單送出),自動傳送到你 App 中某個網址的訊息。你的 App 不必一再詢問是否有變化,而是由另一方主動告訴它。
Webhook 和 API 有什麼區別?
使用 API 時,你的 App 向另一項服務提出請求並取得回應。使用 Webhook 時,則是另一項服務在事件發生時呼叫你的 App。許多整合會同時使用兩者:以 Webhook 得知事件,再透過 API 呼叫取得詳細資料或執行動作。
Webhook 安全嗎?
只要你驗證它們,就可以很安全。設計良好的服務商會使用只有你知道的密鑰為每個 Webhook 簽章,而你的 App 應拒絕任何簽章不符的請求。若沒有這項檢查,任何找到網址的人都可以傳送假事件。
如果 Webhook 送出時我的 App 離線,會發生什麼事?
這取決於服務商。例如 Stripe 在正式模式下,會在最多三天內重試失敗的傳送,而 GitHub 不會自動重試,需要你手動或透過腳本重新傳送。請查閱各服務商的文件,並設計你的處理程式,使其能應付延遲或重複的事件。