Asset Library (Seedance_sup)
The asset library lets you upload and manage portrait assets (virtual / real persons) for digital-human videos and custom avatar generation. All asset operations go through the unified POST/GET /v1/assets endpoint, sharing the same API Key as video generation.
Two asset libraries (per model family)
- This page: asset library for Seedance_sup (
seedance-2-0family), path/v1/assets, asset URI formatasset://asset-xxx; - Native Seedance V3 (
doubao-seedance-*) has its own library at/v3/asset-groups&/v3/assets— see Asset Library V3. - Assets from the two libraries cannot be referenced across (
asset://is bound to the upstream that created it).
Our public interface is a uniform and stable contract: the paths, parameters, and response structures you call stay consistent, so later upgrades won't require code changes on your side.
Two Kinds of Library
kind | Name | Description |
|---|---|---|
virtual | Virtual portrait library | Upload virtual avatars/images/videos directly, no verification |
real | Real-person library | Requires a liveness verification flow before uploading |
Authentication
Authorization: Bearer $YOUR_API_KEYAsset Object (Response Fields)
| Field | Type | Description |
|---|---|---|
asset_id | string | Asset file ID, e.g. ast_xxx |
asset_uri | string | Reference URI, e.g. asset://asset-xxx; use this in video generation |
asset_kind | string | virtual or real |
asset_type | string | image or video |
name | string | Asset name |
status | string | active / failed / deleted etc. |
url | string | Asset URL (if any) |
size_bytes | int | File size |
delete_after | int | Expiry timestamp (0 = never) |
duration_seconds | float | Video duration in seconds (0 for images) |
provider | string | Asset source identifier |
Endpoint Overview
| Operation | Method & Path | Scope |
|---|---|---|
| Upload asset | POST $URL/v1/assets | virtual / real |
| List assets | GET $URL/v1/assets | per-account isolated view |
| Get one | GET $URL/v1/assets/{asset_id} | virtual / real |
| Patch asset | PATCH $URL/v1/assets/{asset_id} | virtual only |
| Delete asset | DELETE $URL/v1/assets/{asset_id} | virtual / real |
| Retry | POST $URL/v1/assets/{asset_id}/retry | virtual only (failed) |
| Create liveness session | POST $URL/v1/assets/liveness/sessions | real |
| Confirm liveness | POST $URL/v1/assets/liveness/sessions/{id}/confirm | real |
| Accept liveness | POST $URL/v1/assets/liveness/sessions/{id}/accept | real |
| Latest session | GET $URL/v1/assets/liveness/sessions/latest | real |
{asset_id} two forms (equivalent)
- File ID:
ast_xxx(theasset_idfrom upload response) - URI-derived ID:
asset-xxx(theasset_uriwithout theasset://prefix)
Do not put the full asset://asset-xxx into the URL path (// breaks routing); strip the asset:// prefix first.
1. Upload POST /v1/assets
Query params: kind (virtual default / real), asset_type (image/video, required), name, session_id (required for real).
Body: raw binary (Content-Type: image/* or video/* + X-Filename header), or multipart/form-data file field.
# virtual (binary)
curl $URL/v1/assets?kind=virtual&asset_type=image&name=avatar.png \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H "Content-Type: image/png" \
-H "X-Filename: avatar.png" \
--data-binary @avatar.png
# real (needs session_id)
curl "$URL/v1/assets?kind=real&asset_type=image&session_id=lvfs_xxx&name=real.png" \
-H "Authorization: Bearer $YOUR_API_KEY" \
-F "file=@real.png"Response:
{
"asset_id": "ast_abc123def456",
"asset_uri": "asset://asset-20260728-abc12",
"asset_kind": "virtual",
"asset_type": "image",
"name": "avatar.png",
"status": "active",
"url": "https://...",
"size_bytes": 123456,
"delete_after": 0,
"duration_seconds": 0,
"provider": "—"
}2. List GET /v1/assets
Returns an isolated per-account view; other accounts' assets are never exposed.
Query params: kind, asset_type, status, search, sort_by (created_at/name/size_bytes), sort_order, page (default 1), page_size (1–100, default 20).
curl "$URL/v1/assets?kind=virtual&asset_type=image&page=1&page_size=20" \
-H "Authorization: Bearer $YOUR_API_KEY"Response: { "assets": [...], "pagination": { "page":1, "page_size":20, "total":1 }, "group": { "exists": true } }
3. Get one GET /v1/assets/{asset_id}
Ownership is verified first (404 if not owned). ?refresh=true refreshes the latest status.
curl "$URL/v1/assets/asset-20260728-abc12?refresh=true" \
-H "Authorization: Bearer $YOUR_API_KEY"4. Patch PATCH /v1/assets/{asset_id}
virtualonly (405 method_not_allowedforreal). Body passes through:name/description/pinned...
5. Delete DELETE /v1/assets/{asset_id}
Ownership is verified first, then the delete is proxied and the local record is soft-marked deleted. The asset_uri can no longer be used after deletion.
6. Retry POST /v1/assets/{asset_id}/retry
virtualonly, typically whenstatus=failed(405forreal).
7. Real-person liveness flow
POST /v1/assets/liveness/sessions→session_id+h5_link;- User completes verification on their phone via
h5_link; POST /v1/assets/liveness/sessions/{id}/confirm→validated;POST /v1/assets/liveness/sessions/{id}/accept(optionalnote) →accepted;- Upload with
kind=real&session_id=....
GET /v1/assets/liveness/sessions/latest returns the most recent accepted session.
curl -X POST $URL/v1/assets/liveness/sessions \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response:
{
"session": {
"session_id": "lvfs_9EIegs6xSuzCSGTr9OO8vyyPK2Z7YA63",
"h5_link": "https://...",
"status": "pending",
"expires_at": 1785003600,
"accepted_at": null
}
}About isolation
Liveness sessions are scoped per channel (shared under the same upstream channel), not per end user. If you need to bind a session to a specific end user, maintain that mapping in your own system.
Referencing in Video Generation
Put the asset_uri into the images field of the video request (passed through verbatim):
curl $URL/v1/videos \
-H "Authorization: Bearer $YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2-0",
"prompt": "Make the person in this photo wave their hand",
"seconds": "5",
"size": "720p",
"images": ["asset://asset-20260728-abc12"]
}'Error Codes
Errors return { "error": { "code": "...", "message": "..." } }.
code | HTTP | Meaning |
|---|---|---|
asset_not_found | 404 | Asset not found or not owned by you |
missing_session_id | 400 | real upload missing session_id |
invalid_kind | 400 | kind not virtual/real |
invalid_asset_type | 400 | asset_type not image/video |
method_not_allowed | 405 | virtual-only endpoint called on real asset (PATCH / retry) |
asset_upstream_unavailable | 503 | Upstream asset channel unavailable |
asset_upstream_error | 502 | Upstream gateway error |
volc_asset_create_failed etc. | 4xx/5xx | Upstream business errors, passed through verbatim |
Notes
- Real-person library only exposes Get / List / Delete (no PATCH / retry supported).
- Lists are isolated per account via the platform
user_assetsownership table; Get/Delete also verify ownership. - Our interface is a stable contract — later upgrades won't require changes to your integration code.
