Seedance 2.0 Material Library
The material library lets you prepare reusable images, videos, and audio files before submitting Seedance 2.0 video tasks. The API manages materials by UniAll.ai user: clients use only their UniAll.ai API key, a local mat_* material ID, and the returned asset:// URI.
This guide reflects the public contract updated on July 29, 2026.
Overview
The shortest integration flow is:
- Create a material with a public HTTP(S) URL and an
Idempotency-Key. - Poll the returned
mat_*ID untilstatusisavailable. - Read the
asset://value fromuri. - Put that URI in a structured image, video, or audio field in the Seedance request.
- Delete the material when it is no longer needed, or let it expire automatically.
The first API version accepts public HTTP(S) URLs only. Direct file upload is not supported.
Base URL And Endpoints
All examples use this Base URL:
https:
| Operation | Endpoint | Result |
|---|---|---|
| Create a material | POST /v1/materials | Starts processing and returns a local mat_* ID. |
| Get a material | GET /v1/materials/{material_id} | Returns current status and the usable URI when available. |
| List materials | GET /v1/materials | Returns the current user's visible materials. |
| Delete a material | DELETE /v1/materials/{material_id} | Cancels or deletes the material workflow. |
Authentication And Idempotency
All material endpoints use the same UniAll.ai API key as video requests:
Authorization: Bearer sk-***
Content-Type: application/json
Material creation also requires an idempotency key:
Idempotency-Key: material-order-20260729-0001
The key must contain 1 to 200 visible ASCII characters, with no spaces or control characters.
- Retrying the same normalized request with the same key returns the same local material workflow.
- Reusing a key for a different request returns
material_idempotency_conflict. - After a timeout or uncertain network result, retry with the original key. Do not generate a new key.
- Use a new key when intentionally creating a new material.
Input URL Requirements
The source URL must:
- use
http://orhttps://; - remain directly reachable while the material is processing;
- work without login, cookies, browser state, custom headers, or private network access;
- return media that matches the declared
type; - remain accessible until the material reaches a terminal status.
Quick Start
1. Create A Material
curl -X POST "https://api.uniall.ai/v1/materials" \
-H "Authorization: Bearer sk-***" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: material-order-20260729-0001" \
-d '{
"url": "https://cdn.example.com/product.png",
"type": "image",
"name": "Product reference"
}'
The API returns HTTP 202 and a local material record:
{
"id": "mat_xxxxxxxxxxxxx",
"object": "material",
"name": "Product reference",
"type": "image",
"status": "processing",
"uri": null,
"preview_url": null,
"created_at": "2026-07-29T10:00:00Z",
"available_at": null,
"expires_at": null
}
2. Wait Until Available
curl "https://api.uniall.ai/v1/materials/mat_xxxxxxxxxxxxx" \
-H "Authorization: Bearer sk-***"
Poll every 3 to 5 seconds. Do not use uri until status is available:
{
"id": "mat_xxxxxxxxxxxxx",
"object": "material",
"name": "Product reference",
"type": "image",
"status": "available",
"uri": "asset://asset-xxxxxxxxxxxxx",
"preview_url": "https://example.com/short-lived-preview.jpg",
"created_at": "2026-07-29T10:00:00Z",
"available_at": "2026-07-29T10:01:00Z",
"expires_at": "2026-07-29T12:01:00Z"
}
3. Use The URI In Seedance
Copy the returned uri into the matching structured media field:
curl -X POST "https://api.uniall.ai/v1/videos" \
-H "Authorization: Bearer sk-***" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance2.0",
"resolution": "720p",
"duration": 6,
"content": [
{
"type": "text",
"text": "Keep the product appearance consistent and use a slow cinematic camera move."
},
{
"type": "image_url",
"image_url": {
"url": "asset://asset-xxxxxxxxxxxxx"
},
"role": "reference_image"
}
]
}'
Do not put an asset:// URI in prompt or another plain-text field. UniAll.ai checks ownership, status, and expiry before the media is submitted for generation. Unknown, expired, deleted, or another user's material is rejected. Regular HTTP(S) media inputs continue to work as documented in the series guide.
Create Materials
POST /v1/materials
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Public HTTP(S) image, video, or audio URL. |
type | string | Yes | image, video, or audio. |
name | string | No | User-facing material name. |
real_person | object | No | Required declaration and callback settings for a real-person image or video. |
real_person.consent_confirmed | boolean | Yes with real_person | Must be the JSON boolean true, confirming that separate consent was obtained. |
real_person.callback_url | string | Yes with real_person | Browser redirect after visual verification. Production URLs must use HTTPS. |
Real-Person Materials
Real-person images and videos require an explicit consent declaration and browser-based liveness verification. Real-person audio is not supported.
curl -X POST "https://api.uniall.ai/v1/materials" \
-H "Authorization: Bearer sk-***" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: real-person-material-20260729-0001" \
-d '{
"url": "https://cdn.example.com/person.jpg",
"type": "image",
"name": "Authorized portrait",
"real_person": {
"consent_confirmed": true,
"callback_url": "https://client.example.com/material-complete"
}
}'
HTTP 202 can return verification_pending with a temporary verification_url:
{
"id": "mat_xxxxxxxxxxxxx",
"object": "material",
"name": "Authorized portrait",
"type": "image",
"status": "verification_pending",
"uri": null,
"preview_url": null,
"verification_url": "https://example.com/temporary-h5-token",
"created_at": "2026-07-29T10:00:00Z",
"available_at": null,
"expires_at": null,
"verification_expires_at": "2026-07-29T10:30:00Z"
}
Have the person open verification_url in a browser and complete the H5 liveness flow. After successful verification, UniAll.ai submits the actual material automatically. Do not call POST /v1/materials again.
The browser then redirects to real_person.callback_url with only these query parameters:
material_id=mat_xxxxxxxxxxxxx&material_status=processing
The callback status can be creating, processing, available, or a verification failure status. The redirect confirms that the verification result was received; it does not guarantee that the material is already available. Continue querying the material record. Background recovery can continue the workflow if the browser callback is lost.
verification_url appears only in the create response or an idempotent replay of that response. Get, list, and delete responses never include it.
Get A Material
GET /v1/materials/{material_id}
Only the user associated with the current API key can retrieve the material. The response does not expose the original input URL, visual-verification identifiers, internal material identifiers, routing details, credentials, temporary H5 tokens, or callback verification state.
Materials are currently valid for two hours after becoming available. At expires_at, the record is archived as deleted; subsequent user detail requests return 404 material_not_found.
List Materials
GET /v1/materials
| Query parameter | Required | Description |
|---|---|---|
type | No | image, video, or audio. |
status | No | creating, verification_pending, processing, available, or delete_pending. |
limit | No | Page size from 1 to 100. Default: 50. |
after | No | Opaque cursor returned by the previous page. |
curl "https://api.uniall.ai/v1/materials?type=image&status=available&limit=20" \
-H "Authorization: Bearer sk-***"
{
"object": "material.list",
"data": [
{
"id": "mat_xxxxxxxxxxxxx",
"object": "material",
"name": "Product reference",
"type": "image",
"status": "available",
"uri": "asset://asset-xxxxxxxxxxxxx",
"preview_url": "https://example.com/short-lived-preview.jpg",
"created_at": "2026-07-29T10:00:00Z",
"available_at": "2026-07-29T10:01:00Z",
"expires_at": "2026-07-29T12:01:00Z"
}
],
"has_more": true,
"next_cursor": "opaque-cursor-value"
}
Pass next_cursor unchanged as after to request the next page. Do not parse or construct cursor values.
The user list excludes failed, verification-failed, verification-expired, deleted, historical expired, and already expired records awaiting archival. These records can remain available to administrators for audit and troubleshooting.
Delete A Material
DELETE /v1/materials/{material_id}
curl -X DELETE "https://api.uniall.ai/v1/materials/mat_xxxxxxxxxxxxx" \
-H "Authorization: Bearer sk-***"
- HTTP
200withstatus=deletedmeans deletion is complete. - HTTP
202withstatus=delete_pendingmeans deletion was accepted and is still processing. - Deleting a material whose real-person verification is incomplete cancels the local workflow.
- Delete is idempotent. A deleted material cannot be used for generation.
Both successful status codes return the full material object used by the detail endpoint.
Material Statuses
| Status | Meaning |
|---|---|
creating | UniAll.ai is initializing the material workflow. |
verification_pending | Waiting for real-person H5 verification. |
verification_failed | Verification failed or the session creation result is uncertain. |
verification_expired | The verification session expired. |
processing | The media was submitted and is being processed. |
available | The material can be used in a generation request. |
failed | Material creation or processing failed. |
delete_pending | Deletion was submitted and is still processing. |
deleted | Deletion is complete. This status can appear in a delete response but not in get or list results. |
verification_failed, verification_expired, and failed are terminal failure states. Replaying the original creation key returns the original failed workflow; use a new Idempotency-Key to create a new material.
Security And Lifecycle Notes
- Treat
verification_urlas a secret because it contains a temporary H5 token. Do not write it to application logs, analytics events, support messages, or public pages. - Do not log complete real-person callback URLs, query parameters, or callback verification state.
preview_urlis short-lived. Do not treat it as permanent storage or distribute it as a stable public link.- Do not depend on the original input URL being returned by get or list endpoints.
- Use only the
asset://URI returned for a currentlyavailablematerial owned by the same user.
Common Errors
Errors use an OpenAI-compatible structure:
{
"error": {
"message": "The material is not available.",
"type": "invalid_request_error",
"code": "material_not_available"
}
}
| Error code | Meaning |
|---|---|
invalid_idempotency_key | Idempotency-Key is missing or invalid. |
invalid_material_request | A URL, type, name, or query parameter is invalid. |
invalid_material_cursor | after is not a cursor returned by this endpoint. |
material_channel_unavailable | The material service is temporarily unavailable or the current model does not support material input. |
material_idempotency_conflict | The same idempotency key was used for a different request. |
material_not_found | The material does not exist, belongs to another user, or has expired and been archived. |
material_not_available | The material is not available, has expired, or was deleted. |
material_not_managed | The asset:// URI is not registered in the current user's UniAll.ai material library. |
visual_verification_consent_required | Consent was not explicitly confirmed for a real-person material. |
invalid_visual_verification_request | The real-person media type or callback URL is invalid. |
visual_verification_create_outcome_uncertain | The first verification-session creation result is uncertain; a duplicate session is not created automatically. |
material_create_outcome_uncertain | The material creation result is uncertain while UniAll.ai performs background reconciliation. |
Error messages contain only public information and do not expose upstream errors, internal routing, or credentials.