# Seedance 2.0 Material Library

> Create, verify, query, list, use, and delete reusable Seedance 2.0 materials through the UniAll.ai API.

Canonical URL: https://docs.uniall.ai/models/video/seedance-2-0/material-library
Locale: en

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:

1. Create a material with a public HTTP(S) URL and an `Idempotency-Key`.
2. Poll the returned `mat_*` ID until `status` is `available`.
3. Read the `asset://` value from `uri`.
4. Put that URI in a structured image, video, or audio field in the Seedance request.
5. 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:

```uri
https://api.uniall.ai
```

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

```http
Authorization: Bearer sk-***
Content-Type: application/json
```

Material creation also requires an idempotency key:

```http
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://` or `https://`;
- 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

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

```json
{
  "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

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

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

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

```http
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.

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

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

```uri
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

```http
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

```http
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. |

```bash
curl "https://api.uniall.ai/v1/materials?type=image&status=available&limit=20" \
  -H "Authorization: Bearer sk-***"
```

```json
{
  "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

```http
DELETE /v1/materials/{material_id}
```

```bash
curl -X DELETE "https://api.uniall.ai/v1/materials/mat_xxxxxxxxxxxxx" \
  -H "Authorization: Bearer sk-***"
```

- HTTP `200` with `status=deleted` means deletion is complete.
- HTTP `202` with `status=delete_pending` means 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_url` as 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_url` is 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 currently `available` material owned by the same user.

## Common Errors

Errors use an OpenAI-compatible structure:

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

## Related Pages

- [Seedance 2.0 Series Guide](/models/video/seedance-2-0/series-guide)
- [Seedance 2.0 Video Generation](/models/video/seedance-2-0)
