素材库
上传图片 / 视频 / 音频到素材库,在视频生成等接口中用 asset:// 引用
视频生成等多模态接口可以用你上传到素材库的图片、视频、音频作为参考。素材只需上传一次,之后在任意请求里用 asset://<ASSET_ID> 引用即可,国内版和海外版格式完全一致。
相比每次请求都传一个 1 小时过期的预签名 URL,用素材库的好处:
- 永久引用,草稿保存再久也不会失效
- 同一张图可以跨多次生成复用,不用重复上传
- 素材可以复用到不同模型、不同任务
三步完成素材引用
1. 创建 AssetGroup(首次)
素材必须挂在一个 AssetGroup 下。一个用户可以有多个 Group。
curl -X POST https://api.xrtoken.ai/v1/asset-groups \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "Name": "我的素材库" }'返回:
{ "GroupId": "asset-group-20260423-abc12", "Name": "我的素材库" }拿到 GroupId 之后复用,不用每次都建新的。
一个 API key 服务多个最终用户时,body 里加 external_user_id,见 第三方 SaaS。
2. 上传文件拿到 URL
两种方式:
方式 A — 走我们的 /v1/files 上传(推荐,OpenAI 兼容):
curl -X POST https://api.xrtoken.ai/v1/files \
-H "Authorization: Bearer $XRT_API_KEY" \
-F 'file=@/path/to/reference.png' \
-F 'purpose=assistants'返回:
{
"id": "file-xxxxxxxx",
"object": "file",
"url": "https://xrtoken-storage-*.tos-*.bytepluses.com/uploads/<user>/<uuid>/reference.png?X-Tos-...",
"bytes": 123456,
"filename": "reference.png",
"purpose": "assistants"
}返回的 url 是 24h 签名 URL,下一步注册 Asset 用它当 URL 字段。如果 24h 内没注册完,可以重新 GET /v1/files/{id} 取一份新签名。
方式 B — 用你自己公网可访问的 URL(必须支持 GET 直接下载图/视频字节,不能是 HTML 页面)。
3. 注册为 Asset
curl -X POST https://api.xrtoken.ai/v1/assets \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"GroupId": "asset-group-20260423-abc12",
"URL": "<上一步的 URL>",
"AssetType": "Image",
"Name": "女主角参考图",
"Moderation": { "Strategy": "Skip" }
}'AssetType 可取 Image / Video / Audio。Moderation.Strategy=Skip 跳过上游内容审查(仅海外版生效,国内忽略)。
返回:
{ "AssetId": "asset-20260423183015-xk4m2", ... }4. 在视频生成里引用
把 image_url.url / video_url.url / audio_url.url 换成 asset://<AssetId> 即可,其它字段不变:
{
"model": "doubao-seedance-2-0-260128",
"content": [
{ "type": "text", "text": "把女主角放到这个场景里走过来" },
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "asset://asset-20260423183015-xk4m2" }
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "asset://asset-20260419234137-txt6j" }
}
],
"duration": 5,
"ratio": "16:9",
"resolution": "720p"
}可以引用 asset:// 的字段
只能放在 URL 类字段里:
| 字段 | 用途 |
|---|---|
image_url.url | 参考图(reference_image)、首帧(first_frame)、尾帧(last_frame) |
video_url.url | 参考视频(reference_video,Seedance 2.0) |
audio_url.url | 参考音频(reference_audio,Seedance 2.0) |
content[].text 里写 asset:// 没用,不会被解析。
混用规则
同一个请求里 asset:// 和普通 https:// URL 可以混用,比如一张参考图用素材库的、另一张临时图用签名 URL 的:
"content": [
{ "type": "text", "text": "..." },
{ "type": "image_url", "role": "reference_image",
"image_url": { "url": "asset://asset-20260423183015-xk4m2" } },
{ "type": "image_url", "role": "reference_image",
"image_url": { "url": "https://your-cdn.com/temp/xxx.png" } }
]限制
- 单个请求里最多 10 个 asset 引用(上游 Ark 限制)
- Asset 有 90 天 TTL(上游 Ark 限制),过期后
asset://会解析失败;长期素材在第 89 天重新注册即可 - Asset 只对创建它的用户可见,用别人的
AssetId会返回 403 asset://前缀 不能 用在text字段里 — 只能在 URL 字段里
火山原生格式(drop-in 兼容)
如果你已经用火山 Ark SDK / Open API 对接过素材库,可以直接把 base URL 指向我们、把 AK/SK 签名换成 Bearer,请求路径、参数、响应格式和官方保持一致,不用改业务代码:
# 创建素材(官方 Action=CreateAsset)
curl -X POST "https://api.xrtoken.net/?Action=CreateAsset&Version=2024-01-01" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"GroupId": "group-2026**********-*****",
"URL": "https://example.com/image.jpg",
"Name": "test",
"AssetType": "Image",
"ProjectName": "default"
}'
# 查询素材(官方 Action=GetAsset)
curl -X POST "https://api.xrtoken.net/?Action=GetAsset&Version=2024-01-01" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "Id": "asset-20260423183015-xk4m2" }'ProjectName 非必填:不传时自动使用网关项目(当前 xrtoken);显式传值(包括 default)则原样透传,尊重你指定的项目。Name 可选。创建、查询、列表、更新、删除和真人核验都走官方 POST /?Action=...,响应沿用火山 ResponseMetadata / Result 信封,并保持素材库的账号隔离(只能操作自己名下的分组和素材)。完整说明见 ARK SDK 兼容。
第三方 SaaS:external_user_id
一个 API key 服务自己的 N 个最终用户时,每次请求带上该用户的 external_user_id,素材组和真人脸就会绑到这个人,其他人看不到、用不了。
不传 = 整个 API key 共享同一个素材池(我们自己 Dashboard 走这条)。
字段规则
| 项 | 值 |
|---|---|
| 字段名 | external_user_id |
| 含义 | 你自己系统里的用户 ID,我们当不透明字符串存 |
| 长度 | 最长 128 字符,超出会被截断 |
| POST / PUT | 放 JSON body |
| GET / DELETE | 放 query:?external_user_id=... |
| 鉴权 | 仍用你的 API key:Authorization: Bearer tr-xxx |
同一条用户链路里,创建、轮询、列表、详情、更新、删除都要传同一个值。 创建会话时传了,轮询 不会 自动带上——服务端没有 BytedToken → external_user_id 的存储。
国内站 https://api.xrtoken.net,海外站 https://api.xrtoken.ai。下面用 $XRT_BASE 表示。
建组 / 传素材
curl -X POST "$XRT_BASE/v1/asset-groups" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"Name": "用户42的素材",
"external_user_id": "end-user-42"
}'curl "$XRT_BASE/v1/asset-groups?external_user_id=end-user-42" \
-H "Authorization: Bearer $XRT_API_KEY"上传素材时,body 里同样带 external_user_id,且 GroupId 必须属于这个人。视频生成里用 asset://<AssetId> 即可。
真人扫码:只轮询(推荐先接)
创建会话时的 external_user_id 不会写进 BytedToken。绑组发生在 validate-result 成功那一次,轮询必须再传。
素材库 CRUD(建组、上传)不需要下面两项。真人扫码要先联系商务开通:账号是 trusted_creator,且已完成 企业认证。公开 API 不能自助开。
curl -X POST "$XRT_BASE/v1/asset-groups/validate-session" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_user_id": "end-user-42"
}'响应(字段可能在顶层,也可能在 Result 里):
{
"BytedToken": "eyJhbGci...",
"H5Link": "https://h5-v2.kych5.com?...",
"QRCodeDataURL": "data:image/png;base64,..."
}把 QRCodeDataURL 放进 <img src>,或让用户打开 H5Link。BytedToken 约 120 秒有效。建议每 5 秒轮询一次,直到成功、失败或超时:
curl -X POST "$XRT_BASE/v1/asset-groups/validate-result" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"bytedToken": "eyJhbGci...",
"external_user_id": "end-user-42"
}'| 响应 | 含义 |
|---|---|
GroupId + "status": "active" | 成功,真人组已绑到 end-user-42 |
没有 GroupId | 还在扫,继续轮询 |
ResponseMetadata.Error | 失败 |
这里不传 external_user_id,组会绑成 NULL。之后用 end-user-42 去列表,看不到这个组。
真人组列表:
curl "$XRT_BASE/v1/asset-groups?type=real_person&external_user_id=end-user-42" \
-H "Authorization: Bearer $XRT_API_KEY"第一方扫码流程见 真人活体。
真人扫码:callback 跳转
适合你有一个完成后的落地页。不需要你开 webhook。开会话时两个字段一起传:
curl -X POST "$XRT_BASE/v1/asset-groups/validate-session" \
-H "Authorization: Bearer $XRT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"callback_url": "https://your.app/face-done",
"external_user_id": "end-user-42"
}'callback_url 必须是 http / https 且带 host。你自己的 query 会保留。
用户扫完后:火山先跳到我们的 /v1/asset-groups/face-callback(你不用调),我们验签、拿 GroupId、按创建时的 external_user_id 绑组,再 302 到你的页面:
- 成功:
https://your.app/face-done?status=success&group_id=group-...&external_user_id=end-user-42 - 失败:
https://your.app/face-done?status=failed(没有group_id)
不传 callback_url → 跳回我们 dashboard,适合自己用 playground。
callback 和轮询可能同时写同一条组。如果同时还在轮询,每次仍要带同一个 external_user_id。不传的话:轮询先到会先写成 NULL,等 callback 再到才会补上。
不要这样做
| 做法 | 结果 |
|---|---|
只在 validate-session 传,轮询不传 | 组绑到 NULL,用该用户 id 列表看不到 |
| 创建、轮询、列表用了三个不同的 id | 彼此看不见 |
| GET 把 id 放 body | GET / DELETE 只认 query |
| 不传 id 去列表 | 隔离失效,可能看到该 API key 下其他人的组 |
直接调 /v1/asset-groups/face-callback | 这是火山跳转用的公开地址,不是给你调的 |
相关 API
- 创建 AssetGroup ·
POST /v1/asset-groups - 列出 AssetGroup ·
GET /v1/asset-groups - 创建 Asset ·
POST /v1/assets - 列出 Asset ·
GET /v1/assets - 删除 Asset ·
DELETE /v1/assets/{id} - 发起真人会话 ·
POST /v1/asset-groups/validate-session - 轮询真人结果 ·
POST /v1/asset-groups/validate-result - 创建视频生成任务 ·
POST /v1/videos/generations