通过 API 回复 TikTok 评论:先验证自有帖子与顶层目标
通过 UnifyPort 回复 TikTok 评论时,先选择已验证属于当前连接账号的帖子,再选择已确认的顶层评论,最后调用 POST /v1/accounts/{account_id}/posts/comments/reply,提交 post_id、comment_id 和 text。这不是私信发送接口,也不支持任意视频评论操作。accepted 只表示请求已接受,不保证公开显示、送达或产生 webhook。
要点
- 将账号、帖子和评论标识一起保存;平台 ID 始终保留为字符串。
- 评论列表只覆盖自有帖子的顶层评论,不是完整的嵌套回复历史。
- 缺少
parent_comment_id,不能单独证明目标是顶层评论。 - 区分可重试的读取和结果不确定的写入;回复超时或回执未确认时,不要自动重发。
先区分评论接口与私信接口
TikTok 官方的 Query Video Comments 文档描述 Research API 的读取能力:用 video_id 查询评论,用 comment_id 查询回复,需要 research.data.basic scope。它与通过已连接账号发布回复是不同契约,不要把其中的数值型 ID、分页参数或授权头复制到 UnifyPort 请求中。
同样,TikTok Business Messaging 与 QR 收件箱对比解决的是私信架构选择。公开评论不是通用消息发送接口的会话目标。
本文使用 UnifyPort 非官方接口,范围限定为当前登录 TikTok 账号自己的帖子。尚未连接消息账号时,先完成 TikTok QR 授权流程。执行操作前确认授权完成且 runtime_status: running。工作空间 API Key 只放在后端,并检查操作人员是否有权访问所选账号。
启用回复按钮前,先读取帖子与评论
四个真实接口构成以下流程:
| 任务 | 方法与 API 路径 | 范围 |
|---|---|---|
| 查找自有帖子 | GET /v1/accounts/{account_id}/posts | 仅当前登录账号的帖子 |
| 查看单个帖子 | POST /v1/accounts/{account_id}/posts/info | 在 JSON 中传 post_id,需要验证归属 |
| 查询评论 | POST /v1/accounts/{account_id}/posts/comments/list | 仅顶层评论,分页参数放在 JSON 中 |
| 回复评论 | POST /v1/accounts/{account_id}/posts/comments/reply | 自有帖子上已确认的顶层目标 |
先使用列出账号帖子,再对选中的帖子调用获取账号帖子。粘贴的视频 URL 不能作为归属证明。
调用列出顶层评论时,发送所选 post_id 与 limit。limit 默认 20,范围 1–50。第一页省略 cursor,空字符串无效。data.has_more 为 true 时,将 data.next_cursor 原样作为下一次请求的 cursor;最后一页不返回该游标。
每条分页链都应绑定原账号和帖子。用返回的 ID 选择目标,不要用数组位置或显示名称。当前页条数较少不意味着可以忽略 has_more,读取失败也不能当作空评论列表。
内容和作者字段只在可用时返回。缺少 text 表示未知,不等于空评论;缺少 created_at 时,不要用本地观察时间填充。post_id 应保留为无前导零的正十进制整数字符串,帖子与评论 ID 都不要转成 JavaScript number。
提交一次经过确认的回复
发送前向操作人员展示所选帖子、评论、账号身份和草稿。建议在应用记录中把这些目标与批准的文本绑定,避免列表刷新后写入目标改变。
下面的示例函数只调用一次回复顶层评论接口。传入经过验证的真实选择和服务端 API Key。它不是完整审批系统,不在本地验证归属,也不自动重试。
async function replyToTikTokComment({
apiKey, accountId, postId, commentId, text
}) {
if (typeof postId !== 'string' || !/^[1-9][0-9]*$/.test(postId)) {
throw new Error('Use the returned post ID string');
}
if (typeof commentId !== 'string' || !commentId.trim() ||
typeof text !== 'string' || !text.trim()) {
throw new Error('Select a comment and provide reply text');
}
if (typeof accountId !== 'string' || !accountId.trim()) {
throw new Error('Select the connected account');
}
const response = await fetch(
`https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/posts/comments/reply`,
{
method: 'POST',
headers: {
'X-Api-Key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
post_id: postId, comment_id: commentId, text
})
}
);
const result = await response.json();
return { httpStatus: response.status, result };
}
空白检查只拒绝空输入,不修改已批准的文本。请求发出后,如果网络调用或响应解析失败,应保留“结果未知”,不要用通用 POST 重试循环包裹这个函数。
按实际结果处理,不虚构确定性
| 结果 | 含义 | 建议处理 |
|---|---|---|
200,data.status: accepted | 请求已接受 | 保存结果,不标记为“已公开显示” |
可选的 data.comment | 获得新评论的可靠回执 | 有则保存,不将其设为接受成功的必要条件 |
403 post_inaccessible | 帖子不可访问,原因未被确定 | 停止并检查访问问题,不标记为已删除 |
404 post_not_found | 已验证帖子不存在 | 刷新选择 |
404 comment_not_found | 验证后未找到目标 | 重新选择;不代表搜索过所有嵌套回复 |
501 unsupported_by_provider | 渠道不支持,或目标已确认是嵌套回复 | 停止操作,不静默改发私信 |
写入回执未确认后的 502 reply_post_comment_failed | 写入结果未知 | 留待复核,不自动重发 |
验证不完整会阻止写入。读取侧的验证不完整可以重试,但这不代表结果未知的回复也能安全重发。之后读取时没有看到回复,不能证明它从未创建,尤其是列表只覆盖顶层评论时。
在应用中串行处理同一目标的写入、阻止重复点击,并将 request_id 与 HTTP 结果一起保存。这些是本地保护措施,不是 API 幂等保证。不要把客户评论正文或 API Key 写进通用日志。
通知是独立接收层,不是回复回执
标准事件目录包含 post.comment.created。仅订阅事件不会开启评论轮询:轮询默认关闭,设置 provider_data.enable_comment: true 后需要启动或重连,在线修改需要重连。先确认当前环境支持且接收端已准备好。启动成功本身不能证明配置已生效;关闭轮询也不会撤回已排队事件。
通知属于尽力而为的信号,可能延迟、重复、乱序或遗漏,不是完整历史,也不保证为每次回复生成回执。按照webhook 投递契约验签,并用事件 ID 去重。即使通知没有 parent_comment_id,回复前仍需验证目标,不能根据缺失字段推断可回复性。
常见问题
能回复任意 TikTok 视频的评论吗?
不能通过本文流程实现。文档要求验证帖子属于当前登录账号,且只允许回复已确认的顶层评论。
accepted 表示回复已显示吗?
不是。接受请求不保证显示或送达。可靠评论回执是可选字段,webhook 也不保证产生。
能分页读取所有嵌套回复吗?
不能。UnifyPort 的评论列表只覆盖顶层评论。TikTok Research API 是另一套读取契约,不能直接替换。
上线前应该测试什么?
测试自有帖子、不可访问帖子、多页列表、字符串 ID 保真、嵌套目标、重复点击和网络结果不确定的情况。这些是建议验收项,不是已完成的测试结果。
下一步与资料
先用列出顶层评论实现只读目标选择,再启用回复提交。
资料核对日期:2026-10-26。
让消息接入变成一条稳定的产品管线。
先用统一 API 跑通发送,再用标准事件把所有入站消息接回业务系统。