Skip to content

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-0 family), path /v1/assets, asset URI format asset://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 ​

kindNameDescription
virtualVirtual portrait libraryUpload virtual avatars/images/videos directly, no verification
realReal-person libraryRequires a liveness verification flow before uploading

Authentication ​

http
Authorization: Bearer $YOUR_API_KEY

Asset Object (Response Fields) ​

FieldTypeDescription
asset_idstringAsset file ID, e.g. ast_xxx
asset_uristringReference URI, e.g. asset://asset-xxx; use this in video generation
asset_kindstringvirtual or real
asset_typestringimage or video
namestringAsset name
statusstringactive / failed / deleted etc.
urlstringAsset URL (if any)
size_bytesintFile size
delete_afterintExpiry timestamp (0 = never)
duration_secondsfloatVideo duration in seconds (0 for images)
providerstringAsset source identifier

Endpoint Overview ​

OperationMethod & PathScope
Upload assetPOST $URL/v1/assetsvirtual / real
List assetsGET $URL/v1/assetsper-account isolated view
Get oneGET $URL/v1/assets/{asset_id}virtual / real
Patch assetPATCH $URL/v1/assets/{asset_id}virtual only
Delete assetDELETE $URL/v1/assets/{asset_id}virtual / real
RetryPOST $URL/v1/assets/{asset_id}/retryvirtual only (failed)
Create liveness sessionPOST $URL/v1/assets/liveness/sessionsreal
Confirm livenessPOST $URL/v1/assets/liveness/sessions/{id}/confirmreal
Accept livenessPOST $URL/v1/assets/liveness/sessions/{id}/acceptreal
Latest sessionGET $URL/v1/assets/liveness/sessions/latestreal

{asset_id} two forms (equivalent)

  • File ID: ast_xxx (the asset_id from upload response)
  • URI-derived ID: asset-xxx (the asset_uri without the asset:// 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.

bash
# 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:

json
{
  "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).

bash
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.

bash
curl "$URL/v1/assets/asset-20260728-abc12?refresh=true" \
  -H "Authorization: Bearer $YOUR_API_KEY"

4. Patch PATCH /v1/assets/{asset_id} ​

virtual only (405 method_not_allowed for real). 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 ​

virtual only, typically when status=failed (405 for real).

7. Real-person liveness flow ​

  1. POST /v1/assets/liveness/sessions → session_id + h5_link;
  2. User completes verification on their phone via h5_link;
  3. POST /v1/assets/liveness/sessions/{id}/confirm → validated;
  4. POST /v1/assets/liveness/sessions/{id}/accept (optional note) → accepted;
  5. Upload with kind=real&session_id=....

GET /v1/assets/liveness/sessions/latest returns the most recent accepted session.

bash
curl -X POST $URL/v1/assets/liveness/sessions \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Response:

json
{
  "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):

bash
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": "..." } }.

codeHTTPMeaning
asset_not_found404Asset not found or not owned by you
missing_session_id400real upload missing session_id
invalid_kind400kind not virtual/real
invalid_asset_type400asset_type not image/video
method_not_allowed405virtual-only endpoint called on real asset (PATCH / retry)
asset_upstream_unavailable503Upstream asset channel unavailable
asset_upstream_error502Upstream gateway error
volc_asset_create_failed etc.4xx/5xxUpstream 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_assets ownership table; Get/Delete also verify ownership.
  • Our interface is a stable contract — later upgrades won't require changes to your integration code.

© 2026 Euno AI. All rights reserved.