文件 · Webhooks
當發生一個你也能從 /freshness 拉到的資料事件時,我們會把 同一份凍結 payload 推送到你的 HTTPS 端點——推即是拉,零雙重真相。投遞以 Standard Webhooks 簽章,失敗會退避重試,並有 SSRF 防護。
語義:at-least-once、不保序
webhook-id 去重,不要假設 exactly-once。POST,Content-Type: application/json。 三個 Standard Webhooks headers:
webhook-id — 事件穩定 id,用它去重webhook-timestamp — unix 秒;驗簽有 5 分鐘容差webhook-signature — v1,<base64 HMAC-SHA256>,簽 {id}.{timestamp}.{body}Body envelope(路由 metadata + 凍結 payload 放在 data):
{
"id": "3f2b0c9e-…",
"type": "revenue.announced",
"occurred_at": "2026-07-10T09:00:00Z",
"dataset": "monthly-revenue",
"symbol": "2330",
"schema_ver": 1,
"data": { "…frozen event payload, verbatim…": true }
}簽章是標準 HMAC-SHA256。用官方庫驗,篡改的 body / 錯的 secret / 過期 timestamp 都會被擋。可直接執行的範例:
Node:examples/webhooks/verify_signature.mjs(npm i standardwebhooks)· Python:examples/webhooks/verify_signature.py(pip install standardwebhooks)
import { Webhook } from "standardwebhooks";
const wh = new Webhook(process.env.WEBHOOK_SIGNING_SECRET); // whsec_…
// Pass the RAW request body (bytes as received) — re-serializing changes the signed bytes.
const event = wh.verify(rawRequestBody, {
"webhook-id": req.headers["webhook-id"],
"webhook-timestamp": req.headers["webhook-timestamp"],
"webhook-signature": req.headers["webhook-signature"],
}); // throws on tampered body / wrong secret / stale timestampfrom standardwebhooks import Webhook
wh = Webhook(os.environ["WEBHOOK_SIGNING_SECRET"]) # whsec_…
event = wh.verify(raw_request_body, {
"webhook-id": headers["webhook-id"],
"webhook-timestamp": headers["webhook-timestamp"],
"webhook-signature": headers["webhook-signature"],
}) # raises on any mismatch所有 payload 都帶 schema_ver: 1 與 not_investment_advice: true;結構凍結。
{
"schema_ver": 1,
"symbol": "2330",
"revenue_month": "2026-06",
"revenue": 331109,
"unit": { "currency": "TWD", "scale": "thousand_twd" },
"data_as_of": "2026-07-10",
"not_investment_advice": true
}statement 為 income | balance | cash_flow。
{
"schema_ver": 1,
"symbol": "2330",
"statement": "income",
"fiscal_period": "2026-Q1",
"report_date": "2026-05-15",
"data_as_of": "2026-05-15",
"not_investment_advice": true
}此事件沒有 symbol,因此只會匹配「未設 symbol filter」的訂閱。
{
"schema_ver": 1,
"dataset": "derivatives-market",
"exposure_status": "public_sellable",
"reconciliation_badge": "green",
"not_investment_advice": true
}失敗(非 2xx、逾時、連線錯誤、遇到 redirect)以指數退避 + 抖動重試,24 小時內最多 8 次。用盡後端點會被自動停用並 email 通知帳號;修好後可在後台重新啟用。每次嘗試逐筆記錄。
169.254.169.254 / fd00:ec2::254) 一律拒絕(含 IPv4-mapped / 6to4 / NAT64)。每個端點有 whsec_… 簽章密鑰,加密儲存(與 API key 相同的 key-reveal 鏈),建立時完整顯示一次,其餘僅能經節流的 reveal 端點取得。可隨時輪替——新密鑰回傳一次,舊的立即停止簽章。
完整參考:docs/WEBHOOKS.md · 返回文件入口