用 GitHub Copilot 建立 TikTok DM Webhook 接收器
要做 TikTok 私訊客服,不要讓 AI 自己猜 TikTok 的 payload。比較可靠的方式,是先把真實 API 契約放進 GitHub Copilot 的上下文:UnifyPort 會把 TikTok 入站訊息整理成標準 message.received 事件,並用 X-Device-Signature 對原始 request body 做 HMAC-SHA256 簽名。
重點整理
- TikTok 官方開發者文件中的私訊資料,主要出現在 Data Portability 的 scope 與資料類型,不是通用即時客服 webhook。
- 讓 Copilot 依照 UnifyPort 文件產生程式:
POST /v1/webhook-endpoints、subscribed_events、signing_secret、X-Device-Timestamp、X-Device-Signature。 - 必須用 raw body 驗簽,再解析 JSON;如果先 parse 再重新序列化,位元組會改變。
- 先儲存事件,再路由到 Slack、CRM 或 AI 分流 worker,會比把商業邏輯塞在入口更穩。
如果你還在判斷 TikTok DM API 的定位,先讀 TikTok DM API:為什麼沒有官方通用端點。如果你需要的是即時 intake,再看 TikTok Data Portability 與即時 DM 的差異。
Demo 長什麼樣
我們要做的是一個小型 Node.js 服務,只有 /webhook route。它接收 UnifyPort 事件,驗證 X-Device-Timestamp 與 X-Device-Signature,解析 message.received,把必要欄位寫進佇列,最後回傳 200。
請把 webhook delivery and signature verification 文件 放在旁邊。這份文件才是 Copilot 的依據,而不是搜尋到的片段或猜測。
第一個 Copilot prompt
Build a minimal Express service for a UnifyPort webhook receiver.
Use express.raw({ type: 'application/json' }). Verify X-Device-Signature as hex HMAC-SHA256 over X-Device-Timestamp + '.' + raw request body using WEBHOOK_SIGNING_SECRET.
Only process event.type === 'message.received'. Store provider, account_id, conversation.id, sender.id, message.id, message.text, message.direction, and occurred_at.
Return 200 after storing; return 401 on invalid signature.
核心程式應該保留 raw body:
import crypto from 'crypto';
import express from 'express';
const app = express();
const secret = process.env.WEBHOOK_SIGNING_SECRET;
const queue = [];
function verifySignature(req) {
const timestamp = req.get('X-Device-Timestamp') || '';
const signature = req.get('X-Device-Signature') || '';
const expected = crypto.createHmac('sha256', secret)
.update(timestamp + '.')
.update(req.body)
.digest('hex');
return signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifySignature(req)) return res.status(401).end();
const event = JSON.parse(req.body.toString('utf8'));
if (event.type !== 'message.received') return res.status(200).end();
queue.push({
provider: event.provider,
account_id: event.account_id,
conversation_id: event.data.conversation.id,
sender_id: event.data.sender.id,
message_id: event.data.message.id,
text: event.data.message.text || '',
direction: event.data.message.direction,
occurred_at: event.occurred_at,
});
res.status(200).end();
});
建立 webhook endpoint
部署 HTTPS endpoint 後,呼叫 POST /v1/webhook-endpoints。subscribed_events 可精準訂閱 message.received,signing_secret 會啟用簽名。
curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
-H "X-Api-Key: dk_live_example" \
-H "Content-Type: application/json" \
-d '{
"url": "https://inbox.example.com/webhook",
"status": "active",
"subscribed_events": ["message.received"],
"signing_secret": "whsec_6f5b1c9d4e7a2b8c"
}'
想看另一個 AI coding workflow,可參考 AI coding agent 自動回覆 bot。
下一步:幂等與路由
第二個 prompt 可以要求 Copilot 加上 X-Device-Event-Id 去重、保存 raw event,並只將 data.message.direction === 'inbound' 的訊息送進客服佇列。之後再接 Slack、CRM 或 AI 分類器。
限制
如果你的產品需要官方內容發布、登入、研究工具或資料匯出,應使用 TikTok 官方 API。UnifyPort 的非官方接口適合既有帳號的即時入站訊息接收;它提供的是可驗證事件流,不是 TikTok 官方 scope。
FAQ
Copilot 可以完成整個 inbox 嗎?
可以協助產生 receiver、測試與佇列程式,但驗簽、密鑰、部署與儲存策略仍要人工檢查。
Data Portability 是即時 DM 嗎?
不是。官方文件描述的是匯出範圍和資料類型;客服場景通常需要即時事件。
要訂閱哪個事件?
入站訊息用 message.received。只有做全事件 collector 時,才使用 ["*"]。
Sources checked on 2026-08-29
讓訊息接入變成一條穩定的產品管線。
先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。