WEBHOOKS

網路鉤子

即時接收 Superroute 事件 — 訂單、狀態變更、追蹤更新。附簽章驗證、自動重試與內建除錯工具。

Webhook 整合指南
開發者中心 首頁

Webhook 整合指南

Webhook 是什麼?

Webhook 就是 Superroute 在事件發生時(訂單建立、配送完成、追蹤更新等),向您設定的 URL 發出的一次 HTTP POST。您建立一個接收端點,我們把事件推送過去。

投遞機制

事件入佇列後非同步發送。每次請求都帶 HMAC-SHA256 簽章,您可驗證它確實來自我們。投遞失敗(非 2xx 或逾時)會以指數退避自動重試最多 5 次。

安全模型

您在設定頁配置共用密鑰,每筆出站 webhook 皆以此簽章。接收端用相同密鑰重新計算並比對 — 一致代表內容真實未經竄改。

事件目錄

共八種出站事件類型。每種事件在設定頁有獨立 URL 欄位,可依需求訂閱任意子集。

訂單已創建

本地配送訂單(送貨 D / 取件 P / 點對點 P2P)建立時觸發,涵蓋所有入口:網頁表單、REST/GraphQL API、電商平台同步、自動規則、匯入列等。Label-service 及其他非配送類型訂單不觸發。若同一收件方同時設定了 order_create_async_postback_url,批次匯入流程中將略過此 webhook(由批次回呼統一通知)。對應欄位 order_create_webhook_url。

載荷範例
訂單.status_change

訂單狀態每次變更時觸發 — 取件、運送中、已送達、異常、取消等。對應欄位 order_status_change_webhook_url。

載荷範例
追蹤事件

包裹生命週期事件觸發時(提交資訊、開始配送、配送成功、未送達等)。對應欄位 tracking_event_webhook_url。「已送達」與「已取件」事件還會附帶簽收憑證:proof_files 以及 proof_files_detail(file_id、type、url、full_url、帶簽章的下載網址)。事件之後才上傳的照片會透過 pod.files_updated 推送。每個檔案還附帶對應事件資訊:tracking_event_id、tracking_event_status_id、tracking_event_key、service_type(1 = delivery / 2 = pickup)和 service_status(1 = success / 2 = failed);未記錄事件的歷史檔案這些欄位為 null。

載荷範例
order.create_async

批次訂單匯入處理完畢後觸發一次,載荷含每列處理結果。對應欄位 order_create_async_postback_url。

載荷範例
POD 附件變更

簽收照片或簽名被新增、取代或刪除時觸發(action:added / updated / removed)——每個檔案一次推送,無需再輪詢附件。設定 pod_files_webhook_url 後啟用。每個檔案還附帶對應事件資訊:tracking_event_id、tracking_event_status_id、tracking_event_key、service_type(1 = delivery / 2 = pickup)和 service_status(1 = success / 2 = failed);未記錄事件的歷史檔案這些欄位為 null。

載荷範例
訂單已刪除

訂單被永久刪除時觸發,便於你的系統同步移除。設定 order_deleted_webhook_url 後啟用。

載荷範例
訂單取消失敗

取消請求被拒絕時觸發(例如訂單已在派送中),便於你的營運管道監控失敗的取消,無需輪詢 API 回應。設定 order_cancel_failed_webhook_url 後啟用。

載荷範例
路線看板席位變更

路線看板席位易主或看板狀態變化時觸發——action 欄位說明發生了什麼(claimed、standby、pooled、promoted、withdrawn、vetoed、replaced、assigned、awarded、lost、displaced、settled、board_opened、board_closed、board_cancelled)。僅限企業層級設定。透過 route_board_webhook_url 訂閱。

載荷範例

供應商智慧櫃事件

面向對接智慧櫃的第三方配送供應商的獨立 webhook 通道。事件投遞到你供應商帳號設定的端點,每個端點可訂閱任意事件子集。

partner_locker.delivery.doors_opened

已開門 — 投櫃嘗試的櫃門打開瞬間觸發——無論司機是在櫃機螢幕上輸入送件碼開門,還是透過遠端開門 API 開門——換格重開也會觸發。opening 資料塊列出每個已打開格口的 grid_id、硬體門板號 compartment_number 和自提櫃格口號 pickup_locker_number(按列從上到下、再從左到右的顯示序號)。每個格口還帶 pickup_locker_code,即收件人要去的「{貨架編碼}-{格口號}」標籤;格口沒有格口號時為 null。負載中還包含 pickup_code——收件人取件碼,開門瞬間即已分配;司機確認放入後仍是同一個碼,但只有在確認放入之後才能用於取件。

載荷範例
partner_locker.delivery.delivered

已投櫃 — 投櫃確認、包裹放入櫃中後觸發。載荷中包含收件人取件碼。每個格口還帶 pickup_locker_code,即收件人要去的「{貨架編碼}-{格口號}」標籤;格口沒有格口號時為 null。透過遠程開門 API 打開的櫃門,櫃機回報全部已開格口關門後由平台自動結算,因此無需呼叫 confirm 也會觸發本事件;confirmed_by 標明結算路徑:courier_terminal、partner_api、door_close、timeout_door_closed 或 console。

載荷範例
partner_locker.pickup.completed

已取件 — 收件人取走已寄存包裹後觸發。

載荷範例
partner_locker.delivery.failed

投遞失敗 — 投遞失敗時觸發;包含每個包裹的失敗代碼。

載荷範例
partner_locker.delivery.expired

已過期 — 未使用的送件碼或未取件的寄存超過有效期時觸發。

載荷範例
partner_locker.delivery.cancelled

已取消 — 投遞在完成前被取消時觸發。

載荷範例
partner_locker.delivery.correction_reopened

修正重開門 — 在糾錯視窗內重新打開已寄存格口以修正放錯位置時觸發——可在櫃機螢幕或透過 API 操作。correction 區塊中列出被重開的格口。每個格口還帶 pickup_locker_code,即收件人要去的「{貨架編碼}-{格口號}」標籤;格口沒有格口號時為 null。

載荷範例
partner_locker.delivery.code_rotated

partner_locker_delivery.event_type_code_rotated — 合作夥伴更換投遞的送件碼或取件碼時觸發。rotation 資料塊說明換的是哪種碼、何時更換、是否重發了收件人通知——新碼本身絕不透過 webhook 傳遞,只在換碼 API 的直接回應中揭示一次。

載荷範例

簽章與驗證: 供應商智慧櫃 webhook 使用獨立的簽名方案:X-Webhook-Signature 為 base64(HMAC-SHA256(金鑰, 時間戳 + "\n" + 投遞 ID + "\n" + 原始報文)),時間戳與投遞 ID 取自 X-Webhook-Timestamp 和 X-Webhook-Delivery-Id 請求標頭。同時請校驗 X-Webhook-Content-Digest(報文的 SHA-256)並拒絕過期時間戳。X-Webhook-Id 在重試之間保持不變——可用於冪等去重。

如何設定: 端點在「第三方配送 → 供應商智慧櫃 → 設定」中管理,每個供應商一個端點,可勾選事件列表。投遞失敗按指數退避最多重試 7 次後進入死信;死信事件可在事件頁面手動重發。

沙盒(模擬櫃機)事件: 針對模擬櫃機建立的投遞會產生與正式環境完全相同的 Webhook 事件,並使用相同金鑰簽章,方便您以真實流量進行開發串接。沙盒事件透過三種方式標記:酬載中攜帶 "livemode": false,event_id 以 PLE-MOCK- 開頭,請求標頭包含 X-Webhook-Test: 1。若端點設定了沙盒網址,沙盒事件將傳送到該網址而非正式網址;未設定時回退到正式網址,但仍帶有標記。「傳送沙盒事件」開關可完全停止沙盒事件的外送。

第三方配送事件

推送給第三方配送服務商(快遞商)的包裹配送 Webhook。涵蓋配送任務的整個生命週期,快遞商不必再輪詢新任務。此類別與下方的智能櫃事件相互獨立:每個服務商按類別分別設定獨立的端點、簽名密鑰和事件訂閱——可在其自己的服務商入口網站中設定,也可由平台營運方設定。

delivery.assignment.created

任務已建立 — 當訂單被指派給服務商時觸發——無論是透過自動規則還是手動指派。載荷包含任務編號、訂單識別碼和包裹追蹤號。

載荷範例
delivery.assignment.handed_over

包裹已移交 — 當倉庫將該任務的全部包裹實際移交給服務商時觸發。

載荷範例
delivery.assignment.cancelled

任務已取消 — 當平台從服務商處撤回任務時觸發。reason 欄位區分 cancelled(任務在承運商處被取消)、fallback_to_self_delivery(平台將訂單收回自行配送)和 reassigned(訂單已改派給其他服務商)。

載荷範例
delivery.assignment.partial_delivered

部分送達 — 當一票貨件中部分包裹已送達、其餘仍在途時觸發。packages 陣列給出每個包裹的結果,legs 列出在承運商處下的第三方訂單——承運商不支援一票多件時,每個包裹一個訂單。

載荷範例

簽章與驗證: 第三方配送 Webhook 使用與供應商智慧櫃 webhook 相同的簽名方案:X-Webhook-Signature 為 base64(HMAC-SHA256(secret, timestamp + "\n" + delivery id + "\n" + raw body)),其中 timestamp 和 delivery id 取自 X-Webhook-Timestamp 和 X-Webhook-Delivery-Id 請求標頭。同時請校驗 X-Webhook-Content-Digest(報文的 SHA-256)並拒絕過期時間戳。X-Webhook-Id 在重試之間保持不變——可用於冪等去重。

如何設定: 服務商可在服務商入口網站(Webhook 設定)中自行設定該端點,平台營運方也可在「第三方配送 → 服務商 → Webhook」中設定。每個服務商一個端點,可勾選事件列表。簽名密鑰可自動產生,也可自訂設定,並可在設定頁面查看。投遞失敗按指數退避最多重試 7 次後進入死信;死信事件可手動重發。設定頁面可隨時發送帶簽名的測試(mock)事件——測試請求攜帶 X-Webhook-Test: 1 請求標頭,且 payload data 中包含 "test": true。

訂單生命週期事件

在經典的 order.status_change Webhook(保持不變)之外提供的細粒度、可選事件:分配給了誰、司機是否接受、包裹何時被取件、在途、送達或失敗,以及司機上下班變化和經過節流的司機位置。在您設定下方 URL 之前不會發送任何內容。

order.assigned

訂單已分配給司機(手動、路線規劃或自動分配)。由編排器分配時 data.source = auto_assign。

載荷範例
order.unassigned

訂單失去了司機(交接、撤銷、拒絕、逾時)。data.previous_driver_id 表示此前是誰持有。

載荷範例
order.accepted

司機在 App 中接受了自動分配的訂單(需要接單的司機上下班模式)。

載荷範例
order.rejected

司機拒絕了已分配的訂單;data.reason 攜帶可選的自由文字原因。

載荷範例
order.pickup_started

司機已開始取件(狀態 開始取貨 / 取貨中)。

載荷範例
order.picked_up

包裹已被取件(狀態 已取件)。

載荷範例
order.on_the_way

包裹正在送往收件人途中(狀態 開始送貨 / 配送中)。

載荷範例
order.completed

配送成功(狀態 遞送成功)。

載荷範例
order.failed

配送嘗試失敗(稍後重派、需重新安排、收件人拒收)。

載荷範例
order.cancelled

訂單已取消。

載荷範例
order.ready

員工(若允許,司機也可以)將訂單標記為可取件(調度選項 → 可取件)。

載荷範例
driver.on_duty_changed

司機在 App 中上班或下班(司機上下班選項)。

載荷範例
driver.location_update

來自 App 或追蹤器的司機位置,按司機透過 driver_location_min_interval_sec 節流(預設 60 秒)。僅發送到 driver_location_webhook_url。

載荷範例

如何設定: 設定 → Webhook(或 GET/PUT /api/v1/webhook-settings、GraphQL webhookSettingsUpdate):order_lifecycle_webhook_url 接收所有 order.* 事件和 driver.on_duty_changed;order_lifecycle_events 可將其收窄為逗號分隔的清單;driver_location_webhook_url 和 driver_location_min_interval_sec 控制 driver.location_update。多個 URL 可用逗號分隔。投遞記錄會以 reference_type order / driver 顯示在 Webhook 投遞日誌中。

簽章與驗證: 簽章方式與您帳戶的其他所有出站 Webhook 完全一致:傳統的 Signature 請求標頭,加上使用您的 webhook_sign_secret 產生的 X-Webhook-Id / X-Webhook-Timestamp / X-Webhook-Signature-V2。重試會重複使用同一個 event_id——請據此去重。

設備訂單事件

針對由您的智慧櫃、自助終端和智慧投遞箱處理之包裹的可選事件:包裹存入設備、被取走、被工作人員取出或超過取件期限,以及該包裹上異常的建立與解決。純新增——現有 Webhook 均不變,設定 device_order_webhook_url 之前不會傳送任何內容。

device_order.stored

包裹已放入設備,正在等待下一位處理人(收件人、快遞員或營運人員,見 data.device_order.next_actor)。due_at 為取件截止時間。

載荷範例
device_order.collected

包裹已被其等待的人取走——收件人、快遞員,或清空智慧投遞箱的工作人員。

載荷範例
device_order.removed

工作人員將包裹從設備中取出。removal_reason 說明原因:overdue_return、handover、relay、anomaly 或 recovery。

載荷範例
device_order.overdue

包裹超過 due_at 仍未被取走。包裹仍在設備中,取件碼依然有效;overdue_at 會被設定,next_actor 變為 operator。

載荷範例
device_order.exception_opened

該包裹的處理上建立了一個異常(例如 door_left_open、deposit_unverified、item_missing、overdue)。data.exception 包含 id、type、severity 與 status。

載荷範例
device_order.exception_resolved

有人關閉了該包裹處理上的異常。data.exception.status 為 resolved 或 dismissed,resolution_action 說明所做的處理。

載荷範例

載荷範例: data.device_order:id, kind, status, next_actor, device_type, device_id, device_name, grid_code, reference_number, order_id, external_order_id, due_at, overdue_at, stored_at, ended_at, removal_reason(時間為 ISO 8601 格式,尚未發生時為 null)。異常事件另含 data.exception:id、type、severity、status、resolution_action。取件碼永遠不會包含在內。event_id 為 DOE-<帳本事件 id>,重試時保持不變。

如何設定: 設定 → Webhooks(或 GET/PUT /api/v1/webhook-settings):device_order_webhook_url 接收所有 device_order.* 事件;device_order_events 可將其限定為逗號分隔的清單。多個 URL 可用逗號分隔。投遞紀錄顯示於 Webhook 投遞日誌中,reference_type 為 device_order。

簽章與驗證: 簽章方式與您帳戶的其他所有出站 Webhook 完全一致:傳統的 Signature 請求標頭,加上使用您的 webhook_sign_secret 產生的 X-Webhook-Id / X-Webhook-Timestamp / X-Webhook-Signature-V2。重試會重複使用同一個 event_id——請據此去重。

合作承運商以其自有帳戶投遞至您櫃中的包裹不會透過此通道傳送;合作方透過其供應商智慧櫃 Webhook 接收這些事件。

如何設定

可在兩個層級設定:商戶級(涵蓋全部)或客戶級(覆寫特定 B2B 子帳號)。

1. 進入設定

登入後前往「設定 → API 與 Webhook」。客戶級覆寫在客戶詳情頁。

2. 設定簽章密鑰

至少 16 字元,建議 32 位元組以上隨機字串,接收端用它驗證簽章。

3. 填您需要的事件 URL

只填您關心的事件 URL,其餘留空即可。

webhook_sign_secret您在設定頁配置共用密鑰,每筆出站 webhook 皆以此簽章。接收端用相同密鑰重新計算並比對 — 一致代表內容真實未經竄改。
order_create_webhook_url本地配送訂單(送貨 D / 取件 P / 點對點 P2P)建立時觸發,涵蓋所有入口:網頁表單、REST/GraphQL API、電商平台同步、自動規則、匯入列等。Label-service 及其他非配送類型訂單不觸發。若同一收件方同時設定了 order_create_async_postback_url,批次匯入流程中將略過此 webhook(由批次回呼統一通知)。對應欄位 order_create_webhook_url。
order_status_change_webhook_url訂單狀態每次變更時觸發 — 取件、運送中、已送達、異常、取消等。對應欄位 order_status_change_webhook_url。
track_event_webhook_url包裹生命週期事件觸發時(提交資訊、開始配送、配送成功、未送達等)。對應欄位 tracking_event_webhook_url。「已送達」與「已取件」事件還會附帶簽收憑證:proof_files 以及 proof_files_detail(file_id、type、url、full_url、帶簽章的下載網址)。事件之後才上傳的照片會透過 pod.files_updated 推送。每個檔案還附帶對應事件資訊:tracking_event_id、tracking_event_status_id、tracking_event_key、service_type(1 = delivery / 2 = pickup)和 service_status(1 = success / 2 = failed);未記錄事件的歷史檔案這些欄位為 null。
order_create_async_postback_url批次訂單匯入處理完畢後觸發一次,載荷含每列處理結果。對應欄位 order_create_async_postback_url。
pod_files_webhook_url簽收照片或簽名被新增、取代或刪除時觸發(action:added / updated / removed)——每個檔案一次推送,無需再輪詢附件。設定 pod_files_webhook_url 後啟用。每個檔案還附帶對應事件資訊:tracking_event_id、tracking_event_status_id、tracking_event_key、service_type(1 = delivery / 2 = pickup)和 service_status(1 = success / 2 = failed);未記錄事件的歷史檔案這些欄位為 null。
order_deleted_webhook_url訂單被永久刪除時觸發,便於你的系統同步移除。設定 order_deleted_webhook_url 後啟用。
order_cancel_failed_webhook_url取消請求被拒絕時觸發(例如訂單已在派送中),便於你的營運管道監控失敗的取消,無需輪詢 API 回應。設定 order_cancel_failed_webhook_url 後啟用。
route_board_webhook_url路線看板席位易主或看板狀態變化時觸發——action 欄位說明發生了什麼(claimed、standby、pooled、promoted、withdrawn、vetoed、replaced、assigned、awarded、lost、displaced、settled、board_opened、board_closed、board_cancelled)。僅限企業層級設定。透過 route_board_webhook_url 訂閱。
device_order_webhook_url針對由您的智慧櫃、自助終端和智慧投遞箱處理之包裹的可選事件:包裹存入設備、被取走、被工作人員取出或超過取件期限,以及該包裹上異常的建立與解決。純新增——現有 Webhook 均不變,設定 device_order_webhook_url 之前不會傳送任何內容。
整合更新指南

API 與 Webhook 的全部新能力——冪等取消、對帳拉取、v2 簽章、新事件——附可直接複製的範例,全部向前相容。

簽章與驗證

每筆出站 webhook 在請求標頭附帶 HMAC-SHA256(十六進位)簽章。接收端須以共用密鑰對原始請求主體重新計算並比對,不符即拒絕。

演算法
HMAC-SHA256 (hex)
標頭名稱
Signature
驗證步驟
  1. 在任何解析或中介軟體改動前,讀取原始請求主體。
  2. 使用 hash_hmac('sha256', rawBody, sharedSecret) 計算簽章並以十六進位輸出。
  3. 以恆定時間比較與 Signature 標頭比對(PHP 用 hash_equals,Node 用 crypto.timingSafeEqual)。
  4. 簽章符合才回應 2xx,否則回 401。
<?php $rawBody = file_get_contents('php://input'); $received = $_SERVER['HTTP_SIGNATURE'] ?? ''; $expected = hash_hmac('sha256', $rawBody, $sharedSecret); if (!hash_equals($expected, $received)) { http_response_code(401); exit('Bad signature'); } $payload = json_decode($rawBody, true); // ... handle event ... http_response_code(200); echo 'ok';
const crypto = require('crypto'); const express = require('express'); const app = express(); app.use('/webhooks/superroute', express.raw({ type: 'application/json' }), (req, res) => { const received = req.header('Signature') || ''; const expected = crypto.createHmac('sha256', sharedSecret) .update(req.body).digest('hex'); if (!crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) { return res.status(401).send('Bad signature'); } const payload = JSON.parse(req.body.toString()); // ... handle event ... res.status(200).send('ok'); });
import hmac, hashlib from flask import Flask, request, abort app = Flask(__name__) @app.route('/webhooks/superroute', methods=['POST']) def webhook(): received = request.headers.get('Signature', '') expected = hmac.new(shared_secret.encode(), request.data, hashlib.sha256).hexdigest() if not hmac.compare_digest(received, expected): abort(401) payload = request.get_json() # ... handle event ... return 'ok', 200
func handleWebhook(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) received := r.Header.Get("Signature") mac := hmac.New(sha256.New, []byte(sharedSecret)) mac.Write(body) expected := hex.EncodeToString(mac.Sum(nil)) if !hmac.Equal([]byte(received), []byte(expected)) { w.WriteHeader(401); return } // ... handle event ... w.WriteHeader(200) w.Write([]byte("ok")) }
require 'openssl' require 'rack/utils' post '/webhooks/superroute' do raw = request.body.read received = request.env['HTTP_SIGNATURE'] || '' expected = OpenSSL::HMAC.hexdigest('sha256', shared_secret, raw) halt 401 unless Rack::Utils.secure_compare(received, expected) payload = JSON.parse(raw) # ... handle event ... status 200 'ok' end

重試與可靠性

接收端應快速回應 2xx。若回非 2xx、逾時或不可達,我們會重試投遞。

最多嘗試
5 次(首次 + 4 次重試)
單次逾時
3 秒
退避策略
指數退避 — 約 10s、100s、1000s、10000s
請實作冪等. 同一事件可能被重試 — 您可能收到多次。請以訂單號 / 追蹤號做去重鍵,已處理 ID 至少快取 24 小時。
建議回應方式. 快速回 HTTP 200,再非同步處理實際業務。勿在 webhook 處理函式內做慢操作 — 會撞到 3 秒逾時。

簽章驗證工具

貼上您收到的載荷、Signature 標頭值與您的密鑰 — 工具在瀏覽器本地重新計算(資料不會離開本頁)並回報是否一致。

發送測試 Webhook

從我們伺服器真實發出一筆帶簽章的 webhook 到您指定的 URL。用以驗證接收端可達、載荷可解析、簽章驗證正確。

最近的 Webhook 投遞記錄

查看您帳戶最近的 webhook 投遞嘗試 — 包含真實生產事件與本頁送出的測試。貼上 Bearer Token 載入。

時間 事件 URL 狀態 HTTP 嘗試 耗時(ms) 測試? 操作
尚無 webhook 投遞記錄。

最佳實務