← 所有文章
教程

TikTok 数据可携带不等于实时私信:搭建客服真正需要的入站队列

TikTok 的开发者接口越来越清晰,但接口文档更清晰,并不代表它刚好解决客服团队眼前的问题。

6 月 4 日,TikTok 在 Data Portability API changelog 中说明,Data Types 文档已更新,用来反映当前支持的数据类别和字段。Data Portability API 产品页说明,这个 API 面向欧洲经济区和英国的 TikTok 用户,允许用户授权把自己的信息传输到另一个应用。当前 data types 页面 也列出了 Direct Messages 作为可导出的类别,字段包括日期、发送方和内容。

这对数据可携带、归档、备份和合规流程有价值。但它不是实时客服收件箱。

如果你的团队做 TikTok Shop、达人营销或直播销售,真正需要的是另一件事:每一条新私信都应该进入队列,被去重,触发 CRM 查询,然后分配给同事或 AI 助手。用户授权的历史导出无法提供这个事件循环。带签名的入站 webhook 可以。

先定义集成要完成的工作

选 API 之前,先把工作流写成普通语言:

  1. 客户发送一条 TikTok 私信。
  2. 后端在几秒内收到这条消息。
  3. 投递带签名,服务端可以确认来源可信。
  4. 消息被存储,因为错过的事件之后无法补回。
  5. 同一个队列以后还能接收 WhatsApp、LINE、Zalo、Telegram 或 X 消息。

TikTok Data Portability API 不是围绕这个顺序设计的。它是用户授权的数据传输产品。申请方需要服务欧洲经济区或英国用户,通过隐私和安全审核,并请求明确的数据范围。它的数据模型围绕导出展开:帖子和资料、活动、私信或完整归档。

这不是客服需要的时间模型。客服问的不是“这个用户能不能导出昨天的归档”,而是“十秒前来的那条消息,我们能不能马上处理”。

UnifyPort 的 webhook 结构

UnifyPort 的 TikTok 非官方接口面向第二种模型。你连接 TikTok 账号,注册 webhook endpoint,并订阅 message.received。客户消息到达后,UnifyPort 会向你的后端发送一个标准事件包:

{
  "id": "evt_7a4d2c91b6",
  "type": "message.received",
  "provider": "tiktok",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-07-05T03:18:42Z",
  "data": {
    "conversation": { "id": "tt_conv_9172", "type": "user", "title": "Mai Nguyen" },
    "sender": { "id": "tt_user_4839", "name": "Mai Nguyen", "type": "user" },
    "message": {
      "id": "tt_msg_20260705_001",
      "type": "text",
      "text": "今晚直播前黑色托特包还有货吗?",
      "direction": "inbound",
      "sent_at": "2026-07-05T03:18:41Z"
    }
  }
}

关键是这个事件包:idtypeprovideraccount_idoccurred_atdata。同一个处理器今天可以处理 provider: "tiktok",明天可以处理 provider: "zalo"。路由层只在平台行为确实不同时再分支。

先注册 endpoint

连接队列之前,先创建 webhook。endpoint 会保存 URL、订阅事件、签名状态和重试策略。设置 signing_secret 后,每次投递都会带上 X-Device-TimestampX-Device-Signature

curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
  -H "X-Api-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/webhook",
  "status": "active",
  "subscribed_events": ["message.received"],
  "signing_secret": "<WEBHOOK_SIGNING_SECRET>"
}'

UnifyPort 使用 HMAC-SHA256 对时间戳、一个点和原始请求体进行签名。必须在解析 JSON 前用原始字节校验。不要先解析再重新序列化,因为那会改变被校验的字节。

import crypto from "crypto";
import express from "express";

const app = express();
const signingSecret = process.env.WEBHOOK_SIGNING_SECRET;

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.get("X-Device-Timestamp");
  const signature = req.get("X-Device-Signature");

  const hmac = crypto.createHmac("sha256", signingSecret);
  hmac.update(timestamp);
  hmac.update(".");
  hmac.update(req.body);
  const expected = hmac.digest("hex");

  const valid =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

  if (!valid) {
    res.status(401).end();
    return;
  }

  const event = JSON.parse(req.body.toString("utf8"));
  if (event.type === "message.received") {
    console.log(event.provider, event.data.sender.id, event.data.message.text);
  }

  res.status(200).end();
});

app.listen(3000);

这已经足够作为入站边界。生产环境可以把事件写入队列,但边界不变:带签名的投递进来,校验后的事件出去。

先存储,再路由

UnifyPort 文档明确说明,webhook 事件是入站流量的唯一记录。没有消息读取 API,也没有错过 payload 后的回补路径。因此队列设计要先围绕存储展开。

第一步写入应按 id 保存事件,同时保存原始请求体或解析后的 JSON、provider、account ID 和 occurred_at。写入成功后,再异步路由:

TikTok message
  -> UnifyPort message.received webhook
  -> Signature verification
  -> Event store keyed by id
  -> Routing queue
  -> CRM lookup, Slack alert, helpdesk ticket, or AI triage

这里也能看清 Data Portability API 应该放在什么位置。导出适合用户授权的数据迁移。实时客服队列适合运营处理。两者可以共存,但不能混为一谈。

只有需要回复时再加入发送流程

有些团队只需要入站分流。有些团队希望队列在人工或 AI 助手决策后生成回复。把回复作为明确的第二步。

发送消息时,UnifyPort 使用 POST /v1/messages,并传入账号、接收人和标准消息体。入站事件会给你 provider、account、sender、conversation 和 message text;回复流程再决定是否发送。

curl -X POST https://api.unifyport.ai/v1/messages \
  -H "X-Api-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "acc_8c21d0",
  "to": { "id": "tt_user_4839", "type": "user" },
  "message": { "type": "text", "text": "黑色托特包还有货,可以在今晚直播前下单。" }
}'

入站和出站应该在代码中保持分离。第一条路径负责捕获和保存客户消息。第二条路径只在业务逻辑决定后发送响应。

为什么 2026 年 7 月要重新区分这件事

TikTok 6 月 4 日的文档更新提醒我们:平台 API 往往只服务某个政策或产品面。Data portability 是用户控制的数据传输。Content Posting 是发布。Display API 是创作者内容展示。这些名字都不自动等于“实时客服私信收件箱”。

小团队常见的时间浪费,是把每一个新文档化的 API 类别都当成客服事件流。更稳的做法是先命名工作流,再选择匹配它时间模型的接口。

如果工作流是导出,就用导出工具。如果工作流是客服,就用 webhook。如果工作流今天覆盖 TikTok、下个月还要覆盖 Zalo 或 LINE,就从一开始保持标准化事件包。

这就是实际分工:TikTok Data Portability 帮用户移动自己的数据;UnifyPort 帮你的客服系统在消息到达时收到它们。