回呼(Webhook)

建單時帶 callback_url(必須是 https:// 開頭),任務轉為終態(完成/失敗)時,系統會主動 POST 通知你的伺服器,不需要輪詢任務狀態。

送出時機

  • 任務完成(status = 20)時送出一次。
  • 任務失敗(status = 30)時送出一次,失敗任務已自動退還積分(見〈積分與計費〉)。
  • 任務被取消不會觸發 webhook(取消是使用者/系統主動終止,非終態通知的設計範圍)。

請求內容

POST {你的 callback_url}
Content-Type: application/json
X-Signature: <HMAC-SHA256 簽名,見下方>
X-Timestamp: 1799999999
{
  "public_id": "01JABCXYZULID",
  "status": 20,
  "error_code": null,
  "payload": null
}

Body 只帶精簡的狀態通知(status 數值意義見〈任務查詢與取件〉),不含 result/files;收到通知後請自行呼叫 GET /api/tasks/{public_id} 取得完整結果。payload 原封不動帶回你建單時送入的 payload 值(沒帶則為 null),可用來夾帶你自己的關聯資訊(如訂單編號),系統本身不解讀這個欄位的內容。

簽名驗證

X-Signature 是以你帳號的 webhook_secret 對「原始 request body 字串」做 HMAC-SHA256 後的十六進位字串:

X-Signature = hash_hmac('sha256', <raw request body>, <your webhook_secret>)

驗證範例(Node.js):

const crypto = require('crypto')

function isValidSignature(rawBody, signatureHeader, webhookSecret) {
    const expected = crypto.createHmac('sha256', webhookSecret).update(rawBody).digest('hex')
    return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
}

務必對原始 body 字串做簽名比對(而非重新序列化過的 JSON),避免序列化順序/空白差異造成簽名不符。X-Timestamp 是送出當下的 unix timestamp,是否比對其新鮮度(防重放)由你自行決定,系統本身不強制檢查這個值。

取得/輪替 webhook_secret

webhook_secret 是帳號層級設定(同帳號下所有任務共用同一組),在 /app/webhook 頁面查看與輪替(JWT 登入態,非 X-Api-Key)。新的 secret 是輪替當下才產生,無法提前取得,因此正確流程是:先完成輪替拿到新 secret,再立即更新你伺服器上的驗簽設定。輪替完成、到你更新驗簽設定這段期間送達的回呼會驗簽失敗;更新完成後,可仰賴下方〈重送策略〉的重試機制,在後續重送時以新 secret 驗證通過、補收這段期間的通知。輪替後舊 secret 立即失效,沒有雙 secret 過渡期。

重送策略

送出失敗(逾時、連線失敗、你的伺服器回應非 2xx)會自動重試,採指數退避:

第幾次重試 距上次的等待時間
1 1 分鐘
2 5 分鐘
3 30 分鐘
4 2 小時
5 6 小時

滿 5 次仍失敗即放棄,不再自動重試。你的伺服器應該保持冪等(同一個 public_id + status 的通知可能收到不只一次)。