Webhook
透過 Webhook 讓你的伺服器即時收到群組事件通知。
群組事件發生 → 群組GM → HTTP POST → 你的伺服器當訂閱的事件發生時,我們會發送 HTTP POST 請求到你指定的 URL。
設定 Webhook
Section titled “設定 Webhook”1. 準備接收端點
Section titled “1. 準備接收端點”你的伺服器需要提供一個 HTTPS endpoint:
// Express.js 範例const express = require('express');const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => { const event = req.body; console.log('收到事件:', event.event);
// 處理事件...
res.status(200).send('OK');});
app.listen(3000);2. 在 Dashboard 設定
Section titled “2. 在 Dashboard 設定”- 前往「設定 > Webhook」
- 輸入你的 Webhook URL
- 選擇要訂閱的事件
- 點擊「儲存」
3. 測試連線
Section titled “3. 測試連線”點擊「發送測試」確認你的伺服器能正確接收。
message.received
Section titled “message.received”新訊息送出時觸發。
{ "event": "message.received", "timestamp": "2025-01-15T08:30:00Z", "data": { "channelId": "C1234567890", "messageId": "msg_001", "sender": { "userId": "U1234567890", "displayName": "王小明" }, "type": "text", "content": "大家早安!" }}member.joined
Section titled “member.joined”新成員加入群組。
{ "event": "member.joined", "timestamp": "2025-01-15T08:30:00Z", "data": { "channelId": "C1234567890", "member": { "userId": "U0987654321", "displayName": "李小華" } }}member.left
Section titled “member.left”成員離開群組。
{ "event": "member.left", "timestamp": "2025-01-15T08:30:00Z", "data": { "channelId": "C1234567890", "member": { "userId": "U0987654321", "displayName": "李小華" } }}file.uploaded
Section titled “file.uploaded”檔案上傳。
{ "event": "file.uploaded", "timestamp": "2025-01-15T08:30:00Z", "data": { "channelId": "C1234567890", "messageId": "msg_002", "sender": { "userId": "U1234567890", "displayName": "王小明" }, "fileType": "image", "fileSize": 102400 }}每個請求都包含簽章以確保來源:
X-Webhook-Signature: sha256=xxxxxxconst crypto = require('crypto');
function verifySignature(payload, signature, secret) { const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(JSON.stringify(payload)) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}
app.post('/webhook', (req, res) => { const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); }
// 處理事件... res.status(200).send('OK');});如果你的伺服器回傳非 2xx 狀態碼,我們會自動重試:
| 重試次數 | 間隔時間 |
|---|---|
| 第 1 次 | 1 分鐘後 |
| 第 2 次 | 5 分鐘後 |
| 第 3 次 | 30 分鐘後 |
超過 3 次重試失敗後,該事件會被標記為失敗。
Webhook 請求有 30 秒逾時。建議先回應再處理:
app.post('/webhook', async (req, res) => { // 立即回應 res.status(200).send('OK');
// 非同步處理 processEventAsync(req.body).catch(console.error);});同一事件可能因重試而多次送達:
const processedEvents = new Set();
function handleEvent(event) { const eventId = `${event.event}-${event.data.messageId || event.timestamp}`;
if (processedEvents.has(eventId)) { return; // 已處理過 }
processedEvents.add(eventId); // 處理事件...}app.post('/webhook', async (req, res) => { try { await processEvent(req.body); res.status(200).send('OK'); } catch (error) { console.error('Webhook error:', error); // 回傳 500 會觸發重試 res.status(500).send('Error'); }});在 Dashboard 的「設定 > Webhook > 推送記錄」查看:
- 發送時間
- 事件類型
- 回應狀態
- 回應時間
- 錯誤訊息
沒有收到請求
Section titled “沒有收到請求”- 確認 URL 使用 HTTPS
- 確認伺服器可從公網存取
- 檢查防火牆設定
- 使用「發送測試」排查
收到重複事件
Section titled “收到重複事件”這是正常的重試機制,請實作冪等處理。
簽章驗證失敗
Section titled “簽章驗證失敗”- 使用原始 request body
- 確認 secret 正確
- 使用 SHA256 演算法