TikTok Shop 挂车发布全流程
上传视频(拿 fileId)→ 拉商品 →(可选)预审 → 挂车发布
TikTok Shop 挂车发布全流程
流程总览
上传视频(TikTok Shop 库,拿一次性 fileId)→ 拉可挂车商品(拿 productId)
→(可选)预审(precheck,自检违规)→ 挂车发布 → 轮询终态全程只需官方返回的 id(
fileId/creatorUserOpenId/productId/taskId),平台不引入任何自造 id。
⚠️ 四条硬规则(TikTok Shop 官方)
这些规则由官方在发布时校验(平台不预检,违规透传官方报错 3001,message 带官方原因):
- fileId 一次性消耗:发布调用即消耗,失败也不能复用。重发必须重新上传视频。
另外
fileId与上传时的账号绑定(官方规则):A 账号上传的视频只能由 A 账号发布——发布时的accountId必须与上传时一致。 - 锚点文案(productTitle):必填,≤30 个字符,不能有标点和 emoji(
车用脚垫✅、好货!❌)。 - 商品必须可挂车:
reviewStatus=APPROVED且有货;商品需与视频内容相关。 - 预审可选但强烈建议(MRD IF-161144):发布接口不要求预审凭证(与官方一致);但官方规则要求违规内容不应发布——
status=failed(violation FAIL)时请修正素材重审,是否发布由你自行判断并承担后果。优质检查(good quality)未过不阻断,仅给优化建议。预审配额 50 次/天/账号,耗尽返回2002。
字段级补充(同为官方校验):
title(视频文案):支持#话题与@提及(@提及 仅互关好友生效,App 内显示为纯文本)isAiGenerated:AI 生成内容必须传true(发布后会带 AI 标识)
下文示例中
$BASE为生产环境地址(https://cli.haina.io),$TOKEN为「API Keys」页创建的 API Token。
第 1 步:上传视频到 TikTok Shop 库
比 TikTok 库多一个表单字段 accountId(= 坐席里 TikTok Shop 绑定的 creatorUserOpenId):
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@demo.mp4" \
-F "library=tts" \
-F "accountId=<creatorUserOpenId>" \
$BASE/v1/videos返回 201:
{
"code": 0,
"data": {
"videoId": "01a08b67-d2e9-7f9-8eebde-d63b0c18",
"fileId": "v12d00gd0024dahajs7og65ihgiis770",
"videoUrl": null,
"expiresAt": null
}
}TikTok Shop 视频存入 TikTok Shop 平台侧,没有 URL 过期概念;生命周期就是「待发布 → 已发布」。
两个 id 的分工:
fileId是官方口径,预审/发布都用它;videoId只是视频库管理 id(查询/删除/v1/videos/{id}用),发布链路不需要。
视频规则汇总(格式/大小/官方规格等硬约束):
| 项 | 规则 |
|---|---|
| 格式 | mp4 / mov(Content-Type video/mp4 / video/quicktime;官方还支持 webm,本平台只收前两种) |
| 大小 | ≤ 100MB(超限 2001;官方上限 1GB,本平台收紧) |
| TikTok 视频官方规格 | 时长 3–600 秒;宽高均 ≥360px;帧率 23–60 FPS(不满足会在发布阶段被官方拒) |
| TikTok 视频有效期 | videoUrl 上传后 7 天有效(平台计时);到期不可发布(2005),需重新上传 |
| TikTok Shop 视频 | fileId 一次性消耗:发布调用即作废(失败也不可复用),重发需重新上传;无 URL 过期概念 |
| 发布频次 | TikTok 发布:官方限制每账号 ≤6 个/分钟、≤15 个/天(批量发布请自行控制节奏,超限会被官方拒绝);TikTok Shop 挂车:平台侧配额(不同账号不同),超限官方报错,发布成功响应可能带 quota 字段提示剩余配额 |
| TikTok Shop 预审配额 | 50 次/天/账号(API 渠道独立计数;同一 fileId 重复提交会多次消耗);耗尽返回 2002,次日恢复 |
第 2 步:拉取可挂车商品
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"accountId":"<creatorUserOpenId>","productType":"shop","pageSize":20}' \
$BASE/v1/products/queryproductType:shop(店铺商品)/showcase(橱窗);省略 = 两组都返回- 分页:拿响应里的
nextPageToken传入下一次的pageToken;翻页必须在单类型下进行(两组游标互相独立) - 数据有 60s 短缓存;加
"fresh": true穿透缓存直取官方 - 前置条件:挂车账号需已在 TikTok Shop 后台配置「选区(selection region)」——未配置时
shop面报3001 invalid params、showcase面报官方明确提示(no selection region)。这是账号配置项(LOCAL 型账号常见),去卖家后台配置后重试
从 products[].id 拿到 productId。商品同步到自己系统的做法见商品同步集成食谱。
第 3 步:预审(可选,建议做)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileId": "v12d00gd0024dahajs7og65ihgiis770",
"accountId": "<creatorUserOpenId>",
"productId": "1732130661919265505",
"productTitle": "车用脚垫"
}' \
$BASE/v1/publish/tts/precheck返回 201:{ "data": { "taskId": "…", "status": "pending" } }(taskId 是官方预审任务 ID,请自行保存)
轮询结果(pending 时服务端会先拉一次官方):
curl -H "Authorization: Bearer $TOKEN" \
$BASE/v1/publish/tts/precheck/<taskId>status=passed→ 预审通过(qualitySuggestions非空只是优化建议,不影响发布)status=failed→ 官方判定违规(violationCheckResult.issues含违规类型与建议;建议不要发布,修正素材后重新上传+预审)status=pending→ 稍后重查
预审结果长这样(官方双 check 结构的真实示例):
{
"code": 0,
"data": {
"taskId": "7493990579714164574",
"status": "failed",
"violationCheckResult": {
"status": "FAIL",
"issues": [
{
"risk": "Pirated Content",
"suggestions": "Your video may include unoriginal content. Creating original content is essential for standing out from the crowd."
}
]
},
"goodQualityCheckResult": {
"status": "FAIL",
"issues": [
{
"code": "LOW_CONTENT_PROMOTIO",
"suggestions": "You can try to showcase the product from multiple perspectives."
}
]
},
"qualitySuggestions": []
}
}怎么读:violationCheckResult 是红线(违规,issues 里的 risk 是违规类型、suggestions 是官方整改建议);goodQualityCheckResult 是加分项(code 是质量短板类型,比如内容促销感不足,FAIL 只意味着「不够优质」,不影响发布资格)。
第 3.5 步(可选):封面图与背景音乐
封面图:上传图片拿 photoUri,发布时传 coverUri(也可只传 coverTimestampMs 截帧;都不传默认首帧):
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@cover.jpg;type=image/jpeg" -F "accountId=<creatorUserOpenId>" \
$BASE/v1/photos
# → { "photoUri": "tos-useast5-…" }(JPG/PNG/WEBP/HEIC/BMP,≤10MB,宽高比 9:16~16:9)背景音乐:搜索电商授权音乐拿 id,发布时传 musicId:
⚠️ 官方规则:传了
musicId会完全覆盖视频原声(包括口播人声),不是混音。 口播讲解类视频不要配 BGM。
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"accountId":"<creatorUserOpenId>","keyword":"love","pageSize":20,"region":"US","language":"en-US"}' \
$BASE/v1/music/search
# → { music: [{id,title,author,coverUrls,playUrls,duration}], hasMore, nextPageToken, searchId }
# 翻页:第 2 页起必须带首页返回的 searchId + pageToken官方分页怪癖(实测):
nextPageToken是数值 offset(按 pageSize 递增),原值回传即可;searchId每次调用都会变,一次翻页链必须在同一次搜索会话内连续传递;带小pageSize的首调用可能返回空数组但hasMore=true——别误判无结果,带返回的 token+searchId 再查一次即得数据。
后台「素材工具」页提供可视化上传/搜索/试听/复制(无需写脚本)。
第 4 步:挂车发布
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileId": "v12d00gd0024dahajs7og65ihgiis770",
"accountId": "<creatorUserOpenId>",
"productId": "1732130661919265505",
"title": "视频文案 #话题",
"productTitle": "车用脚垫",
"isAiGenerated": false,
"coverUri": "tos-useast5-…",
"musicId": "7086563693013518338"
}' \
$BASE/v1/publish/tts返回 201:
{
"code": 0,
"data": {
"publishId": "01a08b68-7b81-725-a1666f-47ce00e9",
"capability": "TTS",
"videoId": "7683890882440908046",
"status": "publish_complete",
"quota": "3/day"
}
}
- 发布无需预审凭证(与官方一致);是否先预审由你决定。
quota为创作者发布配额提示,仅当平台有配额限制时返回;不返回 ≠ 错误。
字段与官方 Post Shoppable Video 的对应关系(如果你在读官方文档,一眼就能对上):
| 本平台字段 | 官方字段(v202607) | 来源 |
|---|---|---|
fileId | video_info.file_id | Upload Video File 返回 |
title | video_info.title | 视频文案(官方必填,缺省报 3001;支持 #话题 @提及) |
isAiGenerated | video_info.is_ai_generated | AI 标识 |
coverUri | video_info.cover_uri | Upload Shoppable Photo File 返回 |
coverTimestampMs | video_info.cover_timestamp_ms | 封面帧毫秒 |
musicId | video_info.music_id | Search Music 返回 |
productId | product_link_info.product_id | 商品接口返回 |
productTitle | product_link_info.title | 锚点文案 |
accountId | 官方走 access token 识别 | 本平台按坐席账号显式指定 |
videoId即 TikTok Shop 侧的视频 ID(官方 video_id)。用它轮询终态(TTS 无 webhook,轮询是唯一路径):curl -H "Authorization: Bearer $TOKEN" \ "$BASE/v1/publish/tts/status?videoId=7683890882440908046"每 5–10 秒查一次,终态为
publish_complete/publish_failed(失败原因在failReason)。后台「发布记录」页对进行中记录也会每 10s 自动收敛。⚠️ 发布记录(
/v1/publish/records)里的videoId是平台视频库 ID,别拿它查状态(必 1005);TikTok Shop 记录的官方 video_id 在记录的shareId字段。
发布后视频在视频库中标记为「已发布」,同一 fileId 再次发布会被官方拒绝(fileId 已消耗,官方报错透传)。
第 5 步(可选):数据回收
挂车视频发布后就是账号上的一条普通帖子(带商品锚点),播放/点赞等指标走「数据洞察」面:
haina tt insight videos --account <同坐席 TikTok 账号> # 拉账号视频列表(含指标),按标题/发布时间找到这条挂车视频⚠️ 两个注意:① TikTok Shop 发布记录里没有 TikTok item_id(官方挂车状态响应只有 TikTok Shop 侧 video_id)——
video/list没有标题/时间筛选器,定位方式是拉列表后在返回行里按caption/create_time自行匹配(列表按发布时间倒序,新发的视频就在第一页);② 该坐席需绑了 TikTok 能力(洞察走 TikTok 发布体系授权),仅绑 TikTok Shop 的坐席无数据回收面。旧端点
GET /v1/publish/stats(将要废弃,1.6.x 移除)本就不支持 TikTok Shop 记录(它是 TikTok 发布专属的记录锚定接口)——挂车数据回收请一律走上面的数据洞察路由。