總覽
以簽章的 HTTP 請求,將 TicketWave 事件接收到你自己的應用程式中。
Webhooks
Webhook 是 TicketWave 傳送給你的 HTTP 請求。每當你的伺服器發生某件事——例如工單開啟、成員被列入黑名單——TicketWave 就會把一個 JSON 主體以 POST 方式送到你擁有的 URL。
這和 Log Channels 的差別在於:log channels 會把 embed 寫進 Discord 讓人閱讀,而 webhooks 則是把原始事件直接交給你的程式碼處理。
Webhooks 是 premium 功能。沒有 premium,就無法建立端點,也不會傳送任何事件。
建立端點
開啟端點頁面
伺服器儀表板 → Webhooks → Endpoints。
新增端點
點擊 Add Endpoint,並填入兩個欄位:
| Field | Description |
|---|---|
| Endpoint URL | 接收請求的 https:// URL |
| Event Types | 這個端點應接收哪些事件 |
端點只會接收你勾選的類型。不允許完全不選——至少要選一個。
複製簽章密鑰
TicketWave 會在端點建立的當下產生一組簽章密鑰(whsec_…)。打開端點清單,點擊眼睛圖示顯示它,然後將其複製到你的應用程式設定中。
請把這個密鑰當成密碼看待。任何拿到它的人都能偽造通過你簽章驗證的請求。請把它放在環境變數中,絕不要放進你的儲存庫。
傳送測試事件
使用端點列上的 Send test event 按鈕(紙飛機圖示)。它會送出一個真實、完整簽章的請求,payload 中包含 "test": true,讓你可以在真正的工單依賴它之前先確認接收端運作正常。
結果會像其他傳送一樣,顯示在 Webhooks 歷史紀錄中。
端點需求
| Requirement | Detail |
|---|---|
| Scheme | 僅限 https:// — http:// 會被拒絕 |
| Host | 必須可公開解析。私有、loopback、link-local 與 CGNAT 位址都會被拒絕 |
| Response | 任何 2xx 狀態都視為成功 |
| Timeout | 你有 10 秒 回應 |
| Redirects | 不會跟隨。3xx 會視為失敗 |
| Limit | 每個伺服器最多 5 個端點 |
主機檢查會在你儲存端點時,以及每一次傳送前都執行一次,所以如果某個網域之後開始解析到內部位址,就會停止傳送到它。
請求內容
每次傳送都是一個帶有 JSON 主體的 POST。
標頭
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | 一律是 JSON |
User-Agent | TicketWave-Webhooks/1.0.5 | 傳送它的 bot 版本 |
X-TicketWave-Event | ticket.created | 事件類型 |
X-TicketWave-Delivery | wh_3f2a… | 這次傳送的唯一 id |
X-TicketWave-Timestamp | 1786224191 | Unix 秒數,簽章的一部分 |
X-TicketWave-Signature | sha256=9f86d0… | 請求的 HMAC |
主體
每個 payload 都使用相同的包裝格式。只有 data 會依事件類型而不同:
{
"event": "ticket.created",
"timestamp": "2026-08-26T08:23:11.000Z",
"guild_id": "123456789012345678",
"data": {
"ticket_id": "ticket-1042",
"ticket_num_id": 1042,
"channel_id": "998877665544332211",
"category": "🤖 Support",
"user": { "id": "987654321098765432", "username": "Luna" },
"created_at": "2026-08-26T08:23:11.000Z"
}
}請參閱 Event Reference 以查看每種類型的 data 物件。
驗證簽章
任何發現你端點 URL 的人都可以向它送出 POST 請求。簽章就是用來分辨真實的 TicketWave 傳送與偽造請求的方法。
一定要驗證。 一個未經驗證、卻會在你的系統中建立或關閉資料的端點,就等於敞開大門。
簽章是如何產生的
TicketWave 會把時間戳記與 原始 請求主體用一個點號串接起來,然後使用你的端點密鑰對結果執行 HMAC-SHA256:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)標頭會帶上這個摘要,並以十六進位編碼與前綴表示:sha256=<digest>。
你的接收端必須做什麼
讀取原始主體。 請用你實際收到的精確位元組來驗證。如果你的框架先解析 JSON,然後你再重新序列化,鍵的順序或空白可能會改變,摘要就會不一致。
使用你的密鑰,對 timestamp + "." + rawBody 重新計算 HMAC。
以固定時間比較(Node 中可用 crypto.timingSafeEqual)。單純的 === 會洩漏時間資訊。
檢查時間戳記是否夠新——預設容許五分鐘是個不錯的做法。時間戳記包含在簽章的 payload 中,因此攻擊者無法用新的時間戳記重放舊請求。
完整實作可見 Example Server 頁面。
重試
失敗的傳送會自動重試。
| Attempts | 3(第一次嘗試加上 2 次重試) |
| Backoff | 1 秒,接著 5 秒 |
| Retried on | 網路錯誤、逾時、408、429 以及任何 5xx |
| Not retried on | 其他所有 4xx——這表示你的端點是刻意拒絕該請求 |
由於重試,你的端點可能會收到同一個事件兩次。請把 X-TicketWave-Delivery 當作冪等鍵:記住你已處理過的 id,並忽略重複項目。
傳送不保證順序。如果兩張工單同時建立,請求可能會以任一順序到達——如果順序對你很重要,請使用主體中的 timestamp 欄位。
傳送歷史
儀表板的 Webhooks 頁面會列出每一次傳送,以及它的狀態、回應碼、耗時與嘗試次數。打開某一列即可查看實際送出的請求 payload,以及你的伺服器回傳的回應。
失敗的傳送可以在詳細頁面中使用 Retry Webhook 重新送出。它會把原始 payload 再次送到同一個端點,並記錄一筆新的傳送。
歷史紀錄會保留 30 天,之後會自動清理。
疑難排解
| Problem | Fix |
|---|---|
| 無法儲存端點 | URL 必須是 https://,且解析到公開位址 |
| 所有項目都顯示失敗,且沒有回應碼 | 請求根本沒有到你這裡——可能是逾時、DNS 失敗或連線被拒絕 |
| 簽章永遠不相符 | 你是在對解析後的主體做雜湊,而不是原始位元組,或是忘了 timestamp + "." 前綴 |
| 傳送過一陣子後就停止 | 檢查你的主機是否開始回傳 4xx——這些不會被重試 |
| 某個事件一直沒收到 | 端點沒有訂閱該類型,或伺服器失去 premium |
| 重複事件 | 重試時屬於預期行為——請根據 X-TicketWave-Delivery 去重 |
下一步
- Event Reference(每個事件及其 payload)
- Example Server(可執行的 Express 接收端)
- Log Channels(相同的事件,但會發送到 Discord)
How is this guide?
