← 所有文章
教學

用 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-endpointssubscribed_eventssigning_secretX-Device-TimestampX-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-TimestampX-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-endpointssubscribed_events 可精準訂閱 message.receivedsigning_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

UnifyPort API

讓訊息接入變成一條穩定的產品管線。

先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。