Visual liveness verification
Visual liveness verification creates a restricted asset group for media that must be bound to a specific real-person identity. It is a group-level verification flow, not a normal file upload. Completing verification does not create an asset_xxx immediately.
Flow
- Create a one-time session with
POST /v1/visual-validate-sessions. - Open the returned
h5_linkon the end user's device and complete the liveness flow. - Poll
POST /v1/visual-validate-resultsuntil the status iscompleted. - Save the returned
group_id. The verified group may initially contain zero assets; that is expected. - Upload the image, video, or audio to that group with
POST /v1/assets/uploads. The upload creates the MoonApiXasset_idandAsset://asset_xxx. - Pass
Asset://asset_xxxto a compatible generation request and check preparation for the target model.
Sessions expire after 30 minutes. h5_link is a one-time, short-lived link for the end user. Do not put it in logs, public pages, or long-lived business data.
1. Create a session
POST /v1/visual-validate-sessionscurl https://moonapix.com/v1/visual-validate-sessions \
-H "Authorization: Bearer <MOONAPIX_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0-sz",
"callback_url": "https://client.example.com/visual-validate/callback"
}'Request fields
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Target model enabled for the current API key with an available liveness-compatible route. Session creation returns 503 if no such route is available. |
callback_url | string | Yes | HTTPS callback URL. It is forwarded as a verification callback parameter; clients must still poll the result endpoint. |
Response
{
"object": "visual_validate_session",
"session_id": "vvs_0123456789abcdefghijklmnopqrstuvwxyzabcd",
"h5_link": "https://example.com/one-time-link",
"expires_at": 1710001800
}Keep the session_id and expires_at from the create response, and give h5_link to the end user. Pass the exact session_id back when polling; do not log the complete link.
2. Open the H5 link
Open h5_link in the user's browser or WebView. After the user completes the requested liveness actions, poll the result endpoint. Create a new session if the link expires, is reused, or the 30-minute session lifetime has elapsed.
3. Poll the result
POST /v1/visual-validate-resultscurl https://moonapix.com/v1/visual-validate-results \
-H "Authorization: Bearer <MOONAPIX_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"session_id":"vvs_0123456789abcdefghijklmnopqrstuvwxyzabcd"}'While processing:
{
"object": "visual_validate_result",
"session_id": "vvs_0123456789abcdefghijklmnopqrstuvwxyzabcd",
"status": "pending"
}When complete:
{
"object": "visual_validate_result",
"session_id": "vvs_0123456789abcdefghijklmnopqrstuvwxyzabcd",
"status": "completed",
"group_id": "group_xxx",
"upstream": {
"group_id": "group-official-example"
}
}The completed result is a MoonApiX group_id, not an asset_id. MoonApiX creates a private group first, so GET /v1/assets?group_id=group_xxx may legitimately return total=0. Repeating a completed result query returns the same group_id.
A completed result may also include upstream.group_id, the original official Volcengine group ID registered for this session. Upload and manage media using the top-level MoonApiX group_id and subsequent asset_id. To resolve the official group ID to your MoonApiX group, use asset ID resolution with the same public model used for the session. A pending result has no asset group; wait for the user to complete verification.
Sessions belong to the API user that created them. Missing, malformed, unknown, expired, or cross-user session IDs return 404. If the route pinned to a session is unavailable, the result query returns 409; temporary verification service failures return a service error.
4. Upload into the verified group
After verification, upload the media that the generation request will use. Include the target model and specify purpose and role where possible.
curl https://moonapix.com/v1/assets/uploads \
-H "Authorization: Bearer <MOONAPIX_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0-sz",
"mode": "asset",
"type": "image",
"purpose": "reference_image",
"role": "reference_image",
"group_id": "group_xxx",
"url": "https://example.com/your-reference.png"
}'The successful upload provides the public identities:
asset_id = asset_xxx
asset_ref = Asset://asset_xxx
group_id = group_xxxOnly media owned by the current user and accepted by the target model can be added. Use the group_id returned by this API; identifiers shown by the verification page or another API cannot replace it.
5. Use the asset in generation
Query the asset for the target model first. Confirm asset.status=ready, preparation.status is ready or not_required, and preparation.generation_ready=true. Then pass Asset://asset_xxx explicitly:
{
"model": "seedance-2.0-sz",
"prompt": "Have @person turn naturally while preserving the identity and clothing.",
"references": [
{
"media_type": "image",
"role": "reference_image",
"url": "Asset://asset_xxx",
"alias": "person"
}
],
"duration": 5,
"size": "720p",
"aspect_ratio": "16:9"
}Ordinary image, video, and audio references do not need liveness verification; use normal asset upload. Verification does not bypass model capabilities or content-safety review.
Common errors
| HTTP status | code | Meaning |
|---|---|---|
400 | invalid_json / model_required / invalid_callback_url | Invalid create body, model, or callback URL; invalid JSON on the result endpoint also returns this status. |
403 | model_access_denied | The API key cannot use the target model. |
404 | session_not_found | The result request has a missing, malformed, unknown, or expired session_id, or the session belongs to another API user. |
409 | session_route_unavailable | The route or credential pinned to the session is no longer available. |
500 | session_creation_failed / result_persist_failed | The server could not create or persist the required session or result state. |
502 | — | The verification service failed to create the session or query its result. |
503 | session_store_unavailable / visual_validation_unavailable | Session storage is unavailable, or no liveness-compatible route is available for the model. |