Real-person asset API
The API caller does not sign in to YingTu, but the represented person must complete identity, consent, and liveness checks on the official ByteDance H5 page.
Endpoint
Base URL
https://yingtu.aiPOST /api/seedance-assets/real-persons/verificationsGET /api/seedance-assets/real-persons/verifications/{verification_id}POST /api/seedance-assets/real-personsGET /api/seedance-assets/real-persons/{id}Authentication
The caller does not sign in to YingTu or Google. Authenticate with a LaoZhang API key using Authorization: Bearer <LAOZHANG_API_KEY>.
| Header | Required | Description |
|---|---|---|
Authorization | Yes | LaoZhang API key using Bearer authentication. |
Content-Type | POST only | Create operations use application/json. |
Request
POST /api/seedance-assets/real-persons/verifications
| Field | Required | Description |
|---|---|---|
callback_url | Yes | HTTPS URL opened after the verification flow. |
language | No | Official H5 language: zh, en, or zh-Hant. Default: zh. |
GET /api/seedance-assets/real-persons/verifications/{verification_id}
| Field | Required | Description |
|---|---|---|
verification_id | Yes | Path parameter returned when the verification was created. |
POST /api/seedance-assets/real-persons
| Field | Required | Description |
|---|---|---|
verification_id | Yes | Must be verified and owned by the same API key. |
image_url | Yes | Public HTTPS URL of a clear front-facing image of the same person. |
name | No | Asset name, up to 64 characters. |
Create request
curl --request POST \
--url https://yingtu.ai/api/seedance-assets/real-persons/verifications \
--header "Authorization: Bearer $LAOZHANG_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"callback_url": "https://customer.example.com/seedance/verified",
"language": "en"
}'curl --request GET \
--url https://yingtu.ai/api/seedance-assets/real-persons/verifications/ver_eyJvcGFxdWUiOiJleGFtcGxlIn0 \
--header "Authorization: Bearer $LAOZHANG_API_KEY"curl --request POST \
--url https://yingtu.ai/api/seedance-assets/real-persons \
--header "Authorization: Bearer $LAOZHANG_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"verification_id": "ver_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"image_url": "https://cdn.example.com/presenter.webp",
"name": "presenter-a"
}'Response example
HTTP/1.1 201 Created
Content-Type: application/json
{
"request_id": "req_01JZEXAMPLE",
"verification_id": "ver_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"status": "requires_user_action",
"verification_url": "https://official-h5.example/?...&lng=en",
"callback_url": "https://customer.example.com/seedance/verified",
"expires_at": "2026-07-29T05:30:00.000Z"
}{
"request_id": "req_01JZEXAMPLE",
"verification_id": "ver_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"status": "pending",
"expires_at": "2026-07-29T05:30:00.000Z"
}{
"request_id": "req_01JZEXAMPLE",
"verification_id": "ver_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"status": "verified",
"expires_at": "2026-07-29T05:30:00.000Z"
}{
"error": {
"code": "verification_pending",
"message": "The represented person has not completed verification.",
"request_id": "req_01JZEXAMPLE",
"retryable": true
}
}{
"error": {
"code": "verification_expired",
"message": "The verification session expired. Create a new session.",
"request_id": "req_01JZEXAMPLE",
"retryable": false
}
}{
"request_id": "req_01JZEXAMPLE",
"id": "ast_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"object": "seedance.asset",
"kind": "real_person",
"name": "presenter-a",
"status": "Processing",
"uri": "asset://asset-20260729-example"
}Verification callback
GET https://customer.example.com/seedance/verified
?verification_id=ver_eyJvcGFxdWUiOiJleGFtcGxlIn0
&result_code=10000result_code=10000 means the official H5 flow completed. Use verification_id from the callback Location for later GET and POST requests: GET still returns HTTP 200 while pending, only an early asset POST returns HTTP 409, and an expired ID returns HTTP 410. The callback never exposes the upstream BytedToken.
Official verification-page languages
The official documentation currently lists lng=zh, lng=en, and lng=zh-Hant. The default is zh. This API applies the language parameter to the returned link.
Recommended mapping: zh→zh, en→en, ru/ja/ko/es→en. Traditional Chinese can use zh-Hant. No official Russian, Japanese, Korean, or Spanish verification page is currently documented.
zh → lng=zh
en → lng=en
ru / ja / ko / es → lng=en
Traditional Chinese → lng=zh-HantCode examples
const headers = {
Authorization: `Bearer ${process.env.LAOZHANG_API_KEY}`,
"Content-Type": "application/json",
};
const begin = await fetch("https://yingtu.ai/api/seedance-assets/real-persons/verifications", {
method: "POST",
headers,
body: JSON.stringify({
callback_url: "https://customer.example.com/seedance/verified",
language: "en",
}),
});
if (!begin.ok) throw new Error(await begin.text());
const session = await begin.json();
const verificationUrl = session.verification_url;
// Deliver verificationUrl only to the represented person's authenticated UI.
// Do not log or persist this short-lived URL.
// After the represented person finishes the official H5 flow:
const callbackVerificationId =
"<verification_id received at your callback URL>";
const verified = await fetch(
`https://yingtu.ai/api/seedance-assets/real-persons/verifications/${callbackVerificationId}`,
{ headers: { Authorization: headers.Authorization } },
).then((response) => response.json());
if (verified.status === "verified") {
const asset = await fetch("https://yingtu.ai/api/seedance-assets/real-persons", {
method: "POST",
headers,
body: JSON.stringify({
verification_id: callbackVerificationId,
image_url: "https://cdn.example.com/presenter.webp",
name: "presenter-a",
}),
}).then((response) => response.json());
console.log(asset);
}import os
import requests
endpoint = "https://yingtu.ai/api/seedance-assets/real-persons"
verification_endpoint = f"{endpoint}/verifications"
headers = {"Authorization": f"Bearer {os.environ['LAOZHANG_API_KEY']}"}
session = requests.post(
verification_endpoint,
headers=headers,
json={
"callback_url": "https://customer.example.com/seedance/verified",
"language": "en",
},
timeout=30,
)
session.raise_for_status()
verification = session.json()
verification_url = verification["verification_url"]
# Deliver verification_url only to the represented person's authenticated UI.
# Do not log or persist this short-lived URL.
# Run this after the represented person completes the official H5 flow.
callback_verification_id = "<verification_id received at your callback URL>"
status = requests.get(
f"{verification_endpoint}/{callback_verification_id}",
headers=headers,
timeout=30,
)
status.raise_for_status()
if status.json()["status"] == "verified":
asset = requests.post(
endpoint,
headers=headers,
json={
"verification_id": callback_verification_id,
"image_url": "https://cdn.example.com/presenter.webp",
"name": "presenter-a",
},
timeout=60,
)
asset.raise_for_status()
print(asset.json())Retrieve asset status
curl --request GET \
--url https://yingtu.ai/api/seedance-assets/real-persons/ast_eyJvcGFxdWUiOiJleGFtcGxlIn0 \
--header "Authorization: Bearer $LAOZHANG_API_KEY"HTTP/1.1 200 OK
Content-Type: application/json
{
"request_id": "req_01JZEXAMPLE",
"id": "ast_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"object": "seedance.asset",
"kind": "real_person",
"status": "Active",
"uri": "asset://asset-20260729-example",
"created_at": "2026-07-29T05:00:00Z",
"updated_at": "2026-07-29T05:01:00Z"
}{
"request_id": "req_01JZEXAMPLE",
"id": "ast_eyJvcGFxdWUiOiJleGFtcGxlIn0",
"object": "seedance.asset",
"kind": "real_person",
"status": "Failed",
"uri": "asset://asset-20260729-example",
"failure": {
"code": "InvalidImage",
"message": "The image did not pass upstream validation."
}
}Errors
| HTTP status | Error code | Description | Retryable |
|---|---|---|---|
| 400 | invalid_request | The request body, field, or parameter value is invalid. | No |
| 401 | invalid_api_key | The API key is missing, invalid, or disabled. | No |
| 403 | resource_not_owned | The verification or asset is not owned by this API key, or the public ID is invalid. | No |
| 403 | capability_unavailable | Private portrait-asset entitlement is not enabled for the service account. | No |
| 409 | verification_pending | Returned only by POST /real-persons while verification is pending; a GET status check still returns HTTP 200 with status=pending. | Yes |
| 410 | verification_expired | A GET verification-status or POST /real-persons request used a verification_id older than the 30-minute lifetime. | No |
| 413 | payload_too_large | The JSON request body exceeds 16 KB. | No |
| 415 | unsupported_media_type | A POST request did not use application/json. | No |
| 429 | rate_limit_exceeded | The API key has reached its request limit. | Yes |
| 500 | internal_error | The service could not complete the request. | No |
| 502 | upstream_error | The upstream asset or verification service returned an error. | Yes |
| 503 | authentication_unavailable | API-key validation is temporarily unavailable. | Yes |
| 503 | service_unavailable | The asset API server configuration is temporarily unavailable. | Yes |
{
"error": {
"code": "invalid_request",
"message": "image_url is required.",
"request_id": "req_01JZEXAMPLE",
"retryable": false
}
}Rate limits and tracing
Each API key can make up to 12 create-operation POST requests per hour; GET status requests are not counted. Upstream entitlement may add limits. A limited request returns 429 with Retry-After in seconds.
Every success and error response includes request_id. Include it in support requests, but never send your complete API key.
X-RateLimit-Limit: <limit>
X-RateLimit-Remaining: <remaining>
X-RateLimit-Reset: <unix-seconds>
Retry-After: <seconds>