06 真人认证 (Visual Validate)
用户通过 H5 页面做人脸识别, 完成后生成可在视频生成中使用的人脸 asset group。
用途
- 生成包含特定人物的视频(比如用户自己)
- 一次认证 → 多次使用同一张脸做不同视频
- 防止滥用他人肖像(认证流程保证脸是真人 + 本人意愿)
工作流
┌────────────────────────────────────────────────────────┐
│ 1. 你后端 → POST /v1/seedance/visual-validate/session │
│ body: {callback_url, project_name} │
│ response: {byted_token, h5_link, callback_url} │
└──────────────┬─────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 2. 把 h5_link 给前端 → 前端在 WebView/浏览器中打开 │
│ 用户在 H5 完成人脸识别 │
│ 上游官方 异步回调你的 callback_url(可选) │
└──────────────┬─────────────────────────────────────────┘
│
│ 用户完成后,你后端调:
▼
┌────────────────────────────────────────────────────────┐
│ 3. 你后端 → POST /v1/seedance/visual-validate/result │
│ body: {byted_token, project_name} │
│ response: {group_id} │
└──────────────┬─────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 4. 用 group_id 引用人脸资产生成视频 │
│ asset://<asset_id> 在视频生成 content 里 │
└────────────────────────────────────────────────────────┘Step 1: 拉起认证会话
callback_url 是必填项
跟之前文档说的 -d '{}' 不同 —— callback_url 字段必填,空字符串会被 400 拒绝。 这个 callback_url 是给上游官方 用的(认证完成时 官方 会 POST 到这里),不是给本网关用的。
如果你只想轮询不用回调,可以填一个你自己控制的、能接 POST 但不做任何处理的 endpoint(返 200 就行)。
curl -X POST https://www.dianlitoken.com/v1/seedance/visual-validate/session \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"callback_url": "https://your-server.com/face-verify-callback",
"project_name": ""
}'请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
callback_url | 必填 | 你自己控制的公网 endpoint, 上游官方用 |
project_name | 选填 | 项目名(给上游审计用), 通常留空 |
返回:
{
"byted_token": "<token>",
"h5_link": "https://upstream.example.com/h5/face-verify?token=...&sts=...",
"callback_url": "<your callback url echoed back>"
}| 字段 | 用途 |
|---|---|
byted_token | 用于 Step 3 拉结果, 必须保留 |
h5_link | H5 认证页面, 必须在浏览器 / WebView 打开 |
callback_url | 回显你传的 callback_url |
Step 2: 让用户在 H5 页面认证
把 h5_link 给前端 / 客户端在浏览器或 WebView 打开。
Web 端
<button onclick="window.open(h5Link, 'face-verify', 'width=400,height=600')">
开始人脸认证
</button>iOS
// SwiftUI
.sheet(isPresented: $showH5) {
WebView(url: URL(string: h5Link)!)
}Android
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(h5Link))
startActivity(intent)React Native / Cordova / Flutter
用各自的 WebView 组件打开 h5_link。
⚠️ 安全 — h5_link 中含 STS 凭据
h5_linkURL 中嵌入了临时 STS 凭据(accessKeyId / secretAccessKey / sessionToken)- 不要把这个 URL 记录到日志 / 上传到分析平台
- 不要通过不安全通道(明文 HTTP / IM)传输
- 平台后端日志已经做了打码处理 — 只记录
h5_link_len,不记内容。 你的服务端也要做同样的事。
# ❌ 错误
print(f"H5 link: {h5_link}") # 暴露 STS
# ✅ 正确
print(f"H5 link length: {len(h5_link)}")Step 3: 查询认证结果
这是同步查询,不是轮询
跟之前文档说的"轮询直到 succeeded"不同 —— 实际接口是一次同步请求:
- 用户完成 H5 认证后,你后端调一次这个接口
- 上游返回了 group_id 就直接返回
{group_id} - 上游还没准备好 → 返回 HTTP 4xx 错误(不是 "pending" 状态)
- 失败也是 HTTP 4xx,带具体错误消息
你的代码不应该在循环里调这个接口。 正确做法:等上游官方 回调你 Step 1 提供的 callback_url 之后再调一次。
curl -X POST https://www.dianlitoken.com/v1/seedance/visual-validate/result \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"byted_token": "<token from Step 1>",
"project_name": ""
}'请求字段:
| 字段 | 必填 | 说明 |
|---|---|---|
byted_token | 必填 | Step 1 返回的 token |
project_name | 选填 | 通常空 |
认证成功
{
"group_id": "<upstream-aigc-group-id>"
}group_id 就是一个新创建的 AIGC asset group, 里面包含了已验证的人脸 assets。 平台自动:
- 记录这个 group 的所有权 → 你这个用户
- 给它打
source=visual_validate,group_type=AIGC的标记
这个 group 可以在 05 素材库 的 List 接口里看到。
认证未完成 / 失败 (HTTP 4xx)
{
"error": {
"code": "upstream_rejected",
"message": "<上游错误描述, 比如 user has not completed verification>",
"type": "new_api_error"
}
}常见原因:
- 用户还没在 H5 完成认证 → 等回调或者让用户重新做
- 用户取消了认证
byted_token已过期
不要在 while 循环里反复调这个接口 — 会被限流。
Step 4: 用 group_id 生成视频
拿到 group_id 后,先调 05 素材库 → List 找到这个 group 下的 asset_id,然后在视频生成请求里引用单个 asset:
curl -X POST https://www.dianlitoken.com/v1/videos \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0-pro",
"content": [
{"type": "text", "text": "图中的人在沙滩上奔跑"},
{
"type": "image_url",
"image_url": {"url": "asset://<asset-id>"},
"role": "first_frame"
}
],
"resolution": "720p",
"duration": 5
}'asset URI 格式
单段 asset://<asset-id>,不是 asset://<group-id>/<asset-id>,也不能直接用 asset://<group-id> 引用整个组让模型选脸 —— 必须指定具体 asset_id。
完整 JavaScript 示例
async function generateVideoWithMyFace(prompt) {
const KEY = 'sk-xxx'
const BASE = 'https://www.dianlitoken.com'
const H = {
'Authorization': `Bearer ${KEY}`,
'Content-Type': 'application/json',
}
// 1. 拉起认证会话(callback_url 是必填)
const sessionRes = await fetch(`${BASE}/v1/seedance/visual-validate/session`, {
method: 'POST',
headers: H,
body: JSON.stringify({
callback_url: 'https://your-server.com/face-verify-callback',
project_name: '',
}),
})
const { byted_token, h5_link } = await sessionRes.json()
// 2. 打开 H5 让用户认证
const popup = window.open(h5_link, 'face-verify', 'width=400,height=600')
// 3. 等用户完成 — 由你的 callback endpoint 触发,或用户点 "已完成" 按钮
// (这里假设你的服务端在 callback 触发时通过 WebSocket / SSE 通知前端)
await waitForUserSignal()
popup?.close()
// 4. 拉结果(一次同步调用)
const resultRes = await fetch(`${BASE}/v1/seedance/visual-validate/result`, {
method: 'POST',
headers: H,
body: JSON.stringify({ byted_token, project_name: '' }),
})
if (!resultRes.ok) {
const err = await resultRes.json()
throw new Error(err.error.message)
}
const { group_id } = await resultRes.json()
// 5. 找出 group 里的第一个 asset(本平台目前需要客户端按 asset 引用)
const groupRes = await fetch(`${BASE}/v1/seedance/asset-groups`, { headers: H })
const groups = (await groupRes.json()).data
// ... 你需要先有 group 下的 asset_id; 上游 GroupId 暂未对外暴露
// 素材列表 — 当前 List 接口仅列 group 不列 assets, 暂以平台升级为准。
// 6. 用 group_id / asset_id 生成视频(假设你已经拿到 asset_id)
const taskRes = await fetch(`${BASE}/v1/videos`, {
method: 'POST',
headers: H,
body: JSON.stringify({
model: 'seedance-2.0-pro',
content: [
{ type: 'text', text: prompt },
{
type: 'image_url',
image_url: { url: `asset://${assetId}` },
},
],
resolution: '720p',
duration: 5,
}),
})
const task = await taskRes.json()
console.log('Task created:', task.id)
return task.id
}认证后能持续多久?
- 一次认证生成的 group 在本平台数据库里永久关联到你这个用户
- 不需要每次生成视频都重新认证
- 想换脸 → 重新走 Step 1-3, 生成新 group
上游官方 那侧的 AIGC group / asset 生命周期由上游决定,如果上游过期 / 删除,视频生成调用会返"asset 不存在" 4xx。
隐私 & 合规
- 用户在 H5 页面会看到 隐私协议 + 真人意愿确认
- 平台不存储原始人脸图,只存上游 group_id
- 用户可以随时通过 05 素材库 的 DELETE 接口删除 group 内的 assets
- 合规义务: 你作为开发者必须告知最终用户这是用本人肖像
错误情况
Step 1 — 拉起会话失败
| HTTP | code | 原因 |
|---|---|---|
| 400 | invalid_request | callback_url 字段缺失或为空 |
| 4xx | upstream_rejected | 上游官方错误,看 message |
| 503 | service_unavailable | 上游渠道未配置 / 暂不可用 |
Step 3 — 用户没完成就调
返回 HTTP 4xx + error.message 描述具体上游错误。 不要重试 — 等回调触发再调。
Step 4 — group 下没有可用 asset
通过 asset:// 引用时, 如果 asset_id 错 / 已删 / 不属于你, 返 403:
{
"error": {
"code": "asset_not_owned",
"message": "asset \"<id>\" not accessible by caller"
}
}关于费用
- 拉起认证会话: 不收费(目前)
- 调拉结果接口: 不收费
- 生成视频(含人脸): 按正常视频价格计算(参考 07 计费)
下一篇: 07 计费 →