创建素材组(真人)
curl --request POST \
--url https://api.gravitex.ai/v1/visual-validate/session \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"channel_id": 123
}
'import requests
url = "https://api.gravitex.ai/v1/visual-validate/session"
payload = {
"name": "<string>",
"description": "<string>",
"channel_id": 123
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', description: '<string>', channel_id: 123})
};
fetch('https://api.gravitex.ai/v1/visual-validate/session', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gravitex.ai/v1/visual-validate/session",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'channel_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gravitex.ai/v1/visual-validate/session"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.gravitex.ai/v1/visual-validate/session")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/visual-validate/session")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}"
response = http.request(request)
puts response.read_bodySeedance 2.0(/generations)
创建素材组(真人)
POST /v1/visual-validate/session(liveness_face)
POST
/
v1
/
visual-validate
/
session
创建素材组(真人)
curl --request POST \
--url https://api.gravitex.ai/v1/visual-validate/session \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"description": "<string>",
"channel_id": 123
}
'import requests
url = "https://api.gravitex.ai/v1/visual-validate/session"
payload = {
"name": "<string>",
"description": "<string>",
"channel_id": 123
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({name: '<string>', description: '<string>', channel_id: 123})
};
fetch('https://api.gravitex.ai/v1/visual-validate/session', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gravitex.ai/v1/visual-validate/session",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => '<string>',
'description' => '<string>',
'channel_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gravitex.ai/v1/visual-validate/session"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.gravitex.ai/v1/visual-validate/session")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/visual-validate/session")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"<string>\",\n \"description\": \"<string>\",\n \"channel_id\": 123\n}"
response = http.request(request)
puts response.read_body简介
真人素材库(group_type: liveness_face)不能通过 创建素材组 直接创建,须先在本接口发起 H5 真人核验,用户完成核验后网关落库素材组。
| 库类型 | group_type | 创建方式 |
|---|---|---|
| 虚拟素材库 | aigc | POST /v1/asset-groups |
| 真人素材库 | liveness_face | 本接口 H5 核验 |
火山方舟
CreateVisualValidateSession 本身不接受 name / description;网关在拿到上游 GroupId 后会立刻调用 UpdateAssetGroup 将这两个字段回写到火山控制台。认证
string
必填
Bearer Token,如
Bearer sk-xxxxxxxxxxstring
application/json请求参数
string
必填
素材组名称(用于落库并回写火山方舟控制台)
integer
上游渠道 ID,省略则自动选择
H5 核验流程
1. 客户端发起核验 → POST /v1/visual-validate/session
↓ 返回 { h5_link, state, ... }
2. 客户端 popup 打开 h5_link,用户完成核验
↓ BytePlus 重定向至网关 /asset-validate-callback.html?state=…&bytedToken=…&resultCode=10000
3. 回调页自动 fetch /v1/visual-validate/result,落库 group_type=liveness_face
↓ window.opener.postMessage({ type: 'gravitex-asset-validate-result', ok, group_id, … })
4. 客户端拿到 group_id,后续上传素材复用 POST /v1/assets(支持 Image / Video / Audio)
POST /v1/visual-validate/result;state 由网关内置回调页自动转发。
请求示例
curl -X POST "https://api.gravitex.ai/v1/visual-validate/session" \
-H "Authorization: Bearer sk-xxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "真人A"}'
响应示例
{
"h5_link": "https://verify.byteplus.com/h5/?token=…&lang=zh-CN&lng=zh",
"state": "<base64url>.<hmac>",
"channel_id": 123,
"byted_token": "bp-token-xxxxxxxx",
"expires_in": 900
}
| 字段 | 说明 |
|---|---|
h5_link | BytePlus 真人核验 H5 页面 URL;网关已附加 lang=zh-CN&lng=zh 默认简体中文 |
state | 网关签发的 HMAC-SHA256 令牌,已绑定 user / channel / group_name / byted_token,供回调页换取结果 |
byted_token | 火山方舟本次核验唯一凭据;回调页会与 state 内值比对 |
channel_id | 实际选中的上游渠道 |
expires_in | state 令牌有效期(秒),固定 900(15 分钟)。不是 H5 页面寿命——BytePlus H5 链接约 120 秒内有效,超时须重新调用本接口 |
客户端通常只需在 popup 中打开
h5_link 并监听 window.message。H5 超时后请关闭 popup、移除监听,并重新 POST /v1/visual-validate/session 获取新链接;建议在客户端设置约 130s 超时兜底。客户端 postMessage
回调页(/asset-validate-callback.html)向 window.opener 投递消息(targetOrigin = '*')。回调页与主页若不同源,建议通过 type 字段识别,而非仅依赖 event.origin。
核验成功:
{
"type": "gravitex-asset-validate-result",
"ok": true,
"group_id": "group-20260512083014-zyxwv",
"name": "真人A",
"channel_id": 123,
"group_type": "liveness_face"
}
{
"type": "gravitex-asset-validate-result",
"ok": false,
"result_code": "10003",
"error": "真人核验未通过:人脸与底图不匹配"
}
const popup = window.open(session.h5_link, 'asset-validate', 'width=480,height=720');
const listener = (event) => {
const data = event.data;
if (!data || data.type !== 'gravitex-asset-validate-result') return;
window.removeEventListener('message', listener);
if (data.ok) {
console.log('素材组创建成功:', data.group_id);
} else {
console.error('核验失败:', data.error, data.result_code);
}
};
window.addEventListener('message', listener);
后续步骤
- 使用返回的
group_id(来自 postMessage,非本接口同步响应)调用 创建素材 - 轮询 列出素材 或 查询单个素材 直至
status: active - 在 创建视频生成任务 中用
asset://引用素材
?group_type=liveness_face)确认组已创建。⌘I
