curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "seedance-2.5",
prompt: "A cinematic 30-second steampunk miniature landscape sequence",
size: "16:9",
resolution: "720p",
duration: 30,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.apimart.ai/v1/videos/generations";
String payload = """
{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
<?php
$url = "https://api.apimart.ai/v1/videos/generations";
$payload = [
"model" => "seedance-2.5",
"prompt" => "A cinematic 30-second steampunk miniature landscape sequence",
"size" => "16:9",
"resolution" => "720p",
"duration" => 30
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer <token>",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01KMCGF6BQGN3X28H3KSR50X5T"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed. Please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient balance. Please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests. Please try again later",
"type": "rate_limit_error"
}
}
{
"error": {
"code": 500,
"message": "Internal server error. Please try again later",
"type": "server_error"
}
}
seedance-2-5
seedance-2.5 Video Generation
- Async API; returns task_id for polling
- Text-to-video / multimodal reference / edit / extend / first–last frame
- Up to 30s per job; up to 30 images + 10 videos + 10 audios as references
- Resolution supports 480p / 720p / 1080p; mp4 or mov output
POST
/
v1
/
videos
/
generations
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "seedance-2.5",
prompt: "A cinematic 30-second steampunk miniature landscape sequence",
size: "16:9",
resolution: "720p",
duration: 30,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.apimart.ai/v1/videos/generations";
String payload = """
{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
<?php
$url = "https://api.apimart.ai/v1/videos/generations";
$payload = [
"model" => "seedance-2.5",
"prompt" => "A cinematic 30-second steampunk miniature landscape sequence",
"size" => "16:9",
"resolution" => "720p",
"duration" => 30
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer <token>",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01KMCGF6BQGN3X28H3KSR50X5T"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed. Please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient balance. Please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests. Please try again later",
"type": "rate_limit_error"
}
}
{
"error": {
"code": 500,
"message": "Internal server error. Please try again later",
"type": "server_error"
}
}
Main changes vs 2.0: max duration 15s → 30s; references 9 images + 3 videos + 3 audios → 30 images + 10 videos + 10 audios; audio-only reference supported; mov output added.
Note: resolution supports 480p / 720p / 1080p (2.0’s 4k is not available on 2.5).
Note: resolution supports 480p / 720p / 1080p (2.0’s 4k is not available on 2.5).
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}'
import requests
url = "https://api.apimart.ai/v1/videos/generations"
payload = {
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const url = "https://api.apimart.ai/v1/videos/generations";
const payload = {
model: "seedance-2.5",
prompt: "A cinematic 30-second steampunk miniature landscape sequence",
size: "16:9",
resolution: "720p",
duration: 30,
};
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.apimart.ai/v1/videos/generations"
payload := map[string]interface{}{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30,
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.apimart.ai/v1/videos/generations";
String payload = """
{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
<?php
$url = "https://api.apimart.ai/v1/videos/generations";
$payload = [
"model" => "seedance-2.5",
"prompt" => "A cinematic 30-second steampunk miniature landscape sequence",
"size" => "16:9",
"resolution" => "720p",
"duration" => 30
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer <token>",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01KMCGF6BQGN3X28H3KSR50X5T"
}
]
}
{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}
{
"error": {
"code": 401,
"message": "Authentication failed. Please check your API key",
"type": "authentication_error"
}
}
{
"error": {
"code": 402,
"message": "Insufficient balance. Please top up and try again",
"type": "payment_required"
}
}
{
"error": {
"code": 429,
"message": "Too many requests. Please try again later",
"type": "rate_limit_error"
}
}
{
"error": {
"code": 500,
"message": "Internal server error. Please try again later",
"type": "server_error"
}
}
Authentication
string
필수
Bearer token auth. Get a key from the API Key page.
Authorization: Bearer YOUR_API_KEY
Request parameters
string
필수
Fixed value:
seedance-2.5boolean
기본값:"false"
비디오 작업을 제출하기 전에 콘텐츠 검토를 실행할지 여부를 지정합니다.사용 예시:감지 시 응답:
true:omni-moderation-latest로 프롬프트와 입력 이미지를 검토false또는 생략: 검토 요청을 보내지 않으며 검토 비용이나 지연이 추가되지 않음(기본값)
- 텍스트:
prompt,negative_prompt - 이미지:
image_urls,image_with_roles[].url,first_frame_image,last_frame_image - 이미지 유형 비공개
asset://소재: 원본 공개 URL을 조회한 후 검토 - Base64 이미지: 공개 URL로 변환한 후 검토
video_urls, audio_urls 및 비디오/오디오 유형 비공개 소재는 검토 모델이 비디오와 오디오를 지원하지 않으므로 검토되지 않습니다.지원 모델 ID: seedance-2.0, seedance-2.0-fast, seedance-2.0-mini, seedance-2.0-face, seedance-2.0-fast-face, seedance-2-0(이전 이름), seedance-2.5.검토 호출 자체는 비디오 요청을 제출한 사용자에게 청구되지 않습니다.- 콘텐츠가 감지되면 HTTP 400(
nsfw_content_detected)이 동기식으로 반환됩니다. 작업과task_id가 생성되지 않으며 비디오 생성 할당량도 차감되지 않습니다 - 검토 서비스를 사용할 수 없거나 시간 초과 또는 잘못된 응답이 발생하면 fail-open으로 처리되어 생성 요청이 계속됩니다. 이 옵션을 절대적인 콘텐츠 안전 보장으로 사용하지 마세요
- 공개 이미지 URL로 확인할 수 없는 입력은 건너뜁니다. 지원하지 않는 모델에서는
nsfw_check: true가 알림 없이 무시됩니다
{
"model": "seedance-2.5",
"prompt": "a cat walking on the beach",
"image_urls": ["https://cdn.example.com/ref.png"],
"nsfw_check": true
}
{
"error": {
"message": "Your request was rejected by content moderation (`nsfw_check` is enabled). Flagged categories: sexual, violence/graphic.",
"type": "nsfw_content_detected",
"param": "",
"code": "nsfw_content_detected"
}
}
string
필수
Prompt. Reference media with
@图片1 / @视频1 / @音频1 (1-based index matching array order). English aliases in prompts may also be used depending on model behavior; keep indices aligned with arrays.Example: "Use @视频1 for first-person framing throughout, @音频1 as BGM, first frame is @图片1"string
기본값:"720p"
Resolution — only:
480p720p(default)1080p
2k / 4k return a sync 400.string
기본값:"adaptive"
Aspect ratio (field name
aspect_ratio is also accepted).Values: 16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptive (default)Edit, extend, and first/last-frame jobs have hard
size constraints — see Task types and constraints.integer
기본값:"5"
Duration in seconds:
4~30-1: model picks duration (pre-charge at the 30s cap; settle to actual length after completion)
boolean
기본값:"true"
Whether to generate audio (alias field name:
audio).true: with audio (default)false: silent video
boolean
기본값:"false"
Add an “AI generated” watermark. Default
false.integer
Random seed. Different seeds usually yield different results for the same request; the same seed is similar but not guaranteed identical.
string
기본값:"mp4"
Output container:
mp4(default)mov: higher color precision — recommended for edit / extend workflows
string
기본값:"auto"
Sub-task type hint:
auto / reference / edit / extend.Passing reference / edit / extend validates that type’s constraints at submit time. Invalid requests return 400, create no task, and charge nothing. See Task types and constraints.array<string>
Reference image URLs, all treated as
reference_image.Supports:- Public URL:
https://example.com/pic.jpg - Private asset:
asset://cm9xxxxxxxx
image_with_roles.- Max 30 images
- Prefer
image_with_rolesfor first/last-frame roles
array<object>
Images with explicit roles.
Example:
표시 Fields
표시 Fields
[
{"url": "https://example.com/first.jpg", "role": "first_frame"},
{"url": "https://example.com/last.jpg", "role": "last_frame"}
]
If
video_urls / audio_urls are present, first_frame / last_frame are auto-converted to reference_image (multimodal reference job).array<string>
Reference videos (
reference_video).Input: video URL or asset ID (asset://...).See Reference video specs.array<string>
Reference audio URLs (
reference_audio). Public URLs or asset://....Max 10; total duration ≤ 30s (each clip 2~30s).2.5 supports audio-only reference (no image/video required).
boolean
기본값:"false"
When
true, the successful result also includes the last-frame image for chaining.array<object>
Tool list for enhancements such as web search.Example:
"tools": [{"type": "web_search"}]
표시 Fields
표시 Fields
string
필수
Tool typeValues:
web_search— web search; generation can ground on online information
Media limits
| Media | Limits |
|---|---|
| Images | ≤30; jpeg / png / webp / bmp / tiff / gif / heic / heif; aspect ratio [0.4, 2.5]; side length [300, 6000]px; each <30MB |
| Videos | See Reference video specs |
| Audio | ≤10; wav / mp3; each [2, 30]s and total ≤30s; each ≤15MB |
Reference video specs
- Input: video URL or asset ID (
asset://...) - Container:
mp4,mov— codecs in the table below - Resolution:
480p,720p,1080p - Duration: each clip [2, 30] s; up to 10 reference videos; total duration of all videos ≤ 30s
- Per-video dimensions:
- Aspect ratio (width/height): [0.4, 2.5]
- Side length (px): [300, 6000]
- Total pixels: [640×640=409600, 3326×2494=8295044], i.e. width × height must fall in [409600, 8295044]
- Size: each video ≤ 200 MB
- Frame rate (FPS): [24, 60]
Supported codecs
| Container | Video codec | Audio codec |
|---|---|---|
mp4 | H.264 / H.265 | AAC / MP3 |
mov | H.264 / H.265 | AAC / MP3 |
Task types and constraints
The service infers task type from references and prompt intent. The last three types hard-constrainsize / duration; violations fail asynchronously after the job starts (e.g. InvalidParameter.TaskTypeConstraint):
| Task type | Trigger | Constraints |
|---|---|---|
| Text-to-video | Text only | None |
| Reference-to-video | References + normal descriptive prompt | None. Avoid words like “edit / extend / continue / delete / replace” in the prompt to prevent misclassification |
| Video edit | References + prompt with “edit video / add / delete / modify / replace”, etc. | size must be adaptive, duration must be -1; source video 4~30s |
| Video extend | References + prompt with “extend forward/backward / continue / sequel” | size must be adaptive |
| First / first–last frame | image_with_roles uses first_frame / last_frame | size must be adaptive (also checked at submit time) |
Turn async errors into sync errors with omni_reference_task_type
Passing reference / edit / extend declares the sub-task type so its constraints are validated at submit time. Invalid requests return 400 immediately: no task is created and nothing is charged — you do not have to poll until failed.
| Value | Meaning | Constraints checked at submit |
|---|---|---|
auto (default) | Model infers the type | None (violations fail asynchronously) |
reference | Reference-to-video | None (size / duration unrestricted) |
edit | Video edit | At least one item in video_urls; size must be adaptive (or omitted); duration must be -1 (or omitted, see below); source video 4~30s |
extend | Video extend | At least one item in video_urls; size must be adaptive (or omitted) |
- If
editomitsduration, the platform sets it to-1. Omittingdurationotherwise defaults to 5 seconds, which conflicts with the upstreameditrequirement of-1. The trade-off is a 30-second prepaid hold (same asduration: -1); unused amount is refunded after completion. For a smaller hold, skipeditand use defaultauto. - If
editsendsdurationexplicitly, it must be-1. Any other value returns 400 (output length follows the source video). - ⚠️ You can still fail asynchronously with
InvalidParameter.TaskTypeMismatch. Upstream re-classifies the job from the prompt; a mismatch with your declared type is rejected. Keep prompt wording aligned (edit: “edit / delete / replace…”;extend: “extend forward/backward / continue…”). - All Seedance 2.5 channels share the same validation and upstream payload; switching channels does not change this behavior.
Asset library
You can pass public URLs as references, or upload into the library first and useasset://. Prefer the library when:
- Real human faces must use the library — raw URLs are blocked by content moderation; only approved library assets can be used
- Assets are reused often — upload once, skip repeated moderation on later jobs, faster submits
- URLs are signed temporary links — the platform stores a durable copy on ingest so later use does not depend on the original URL staying alive
- Library assets are synced to all available channels so multi-channel routing can use them wherever the job lands
asset:// IDs work in both 2.0 and 2.5 generation requests. Full submit fields: also see Private avatar assets.
Upload assets
POST /v1/seedance2/private-avatar/assets
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
curl --request POST \
--url https://api.apimart.ai/v1/seedance2/private-avatar/assets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.5",
"group": { "name": "my-assets" },
"asset_type": "Image",
"assets": [
{ "url": "https://example.com/a.png", "name": "a" },
{ "url": "https://example.com/b.png", "name": "b" }
]
}'
| Field | Required | Description |
|---|---|---|
model | No | Model the assets will be used with (defaults to 2.0). Sets the duration tier; for 2.5 pass seedance-2.5 |
group | No | Asset group; created automatically if omitted |
asset_type | Yes | Image / Video / Audio |
assets[].url | Yes | Public media URL |
assets[].name | No | Asset name |
id. Poll with Get task status (GET /v1/tasks/{id}). After approval, list assets to obtain the asset:// ID.
Media limits (validated at submit)
Violations return 400 immediately (which asset index and which rule), without starting moderation or consuming moderation quota:| Media | Limits |
|---|---|
| Image | jpeg / png / webp / bmp / tiff / gif / heic / heif; side length [300, 6000]px; aspect ratio [0.4, 2.5]; each <30MB |
| Video | mp4 / mov; each ≤200MB; duration by model: 2.0 family [2, 15]s, 2.5 [2, 30]s |
| Audio | wav / mp3; each ≤15MB; duration tiers same as video |
{
"error": {
"code": "invalid_asset_material",
"message": "video #1: duration must be between 2s and 15s for seedance-2.0 (got 30s)"
}
}
For 30s video assets, submit with
If the platform cannot probe the media (e.g. network blip), it may pass through and leave the decision to moderation.
"model": "seedance-2.5" (2.0 cannot use assets longer than 15s).If the platform cannot probe the media (e.g. network blip), it may pass through and leave the decision to moderation.
Use in generation requests
Reference approved assets withasset:// in image_urls / image_with_roles / video_urls / audio_urls:
{
"model": "seedance-2.5",
"prompt": "The person in @图片1 walks along the beach",
"image_urls": ["asset://cm9xxxxxxxx"],
"duration": 8
}
Management APIs (quick reference)
| Method | Path | Purpose |
|---|---|---|
GET | /v1/seedance2/private-avatar/assets | List assets |
GET | /v1/seedance2/private-avatar/assets/{asset_id} | Asset detail (incl. moderation status) |
PATCH | /v1/seedance2/private-avatar/assets/{asset_id} | Update asset metadata |
DELETE | /v1/seedance2/private-avatar/assets/{asset_id} | Delete asset |
POST / GET / PATCH / DELETE | /v1/seedance2/private-avatar/groups[/{id}] | Asset group management |
FAQ
Q: How long does moderation take?Images usually seconds; video and real-person assets may take minutes. Poll the task
id until a terminal status.
Q: Moderation failed with no clear reason?Some failures omit a detailed reason (often a transient fetch failure). The platform already retries once; if it still fails, change the URL (ensure it is publicly downloadable) and resubmit. Q: Same asset for both 2.0 and 2.5 — upload twice?
No. Upload once;
asset:// works for both generations. Cross-channel / cross-model sync is handled by the platform.
Q: Can I pass a real-person face as a raw URL?Real-person assets must go through the library first.
Billing
- Billed by seconds × resolution tier.
- With reference video input: billable seconds = total input video duration (≤30s) + output duration, at the input-reference rate tier.
duration = -1(auto): pre-charge at the 30s cap; settle to actual output after completion.- Omit
duration: generate and bill 5 seconds. - Failed jobs or content moderation blocks: full refund (charge only on successful output).
Request examples
Text-to-video (30s)
{
"model": "seedance-2.5",
"prompt": "A cinematic 30-second steampunk miniature landscape sequence",
"size": "16:9",
"resolution": "720p",
"duration": 30
}
Multimodal reference (image + video + audio)
{
"model": "seedance-2.5",
"prompt": "Use @视频1 for first-person framing, @音频1 as BGM, first frame is @图片1",
"image_urls": [
"https://example.com/pic1.jpg",
"https://example.com/pic2.jpg"
],
"video_urls": ["https://example.com/ref.mp4"],
"audio_urls": ["https://example.com/bgm.mp3"],
"size": "16:9",
"duration": 11
}
Video edit
{
"model": "seedance-2.5",
"prompt": "Edit the video: remove all passers-by in @视频1, keep only the main character",
"video_urls": ["https://example.com/input.mp4"],
"size": "adaptive",
"duration": -1,
"output_format": "mov"
}
First–last frame
{
"model": "seedance-2.5",
"prompt": "The girl in the image says \"cheese\" to the camera, 360-degree orbit shot",
"image_with_roles": [
{"url": "https://example.com/first.jpg", "role": "first_frame"},
{"url": "https://example.com/last.jpg", "role": "last_frame"}
],
"size": "adaptive",
"duration": 5
}
Private asset
{
"model": "seedance-2.5",
"prompt": "A person walking naturally on a city street in sunlight",
"image_urls": ["asset://cm9xxxxxxxx"],
"duration": 5,
"resolution": "720p"
}
Web search
{
"model": "seedance-2.5",
"prompt": "Generate a short tech-news video intro based on the latest information",
"size": "16:9",
"resolution": "720p",
"duration": 8,
"tools": [{"type": "web_search"}]
}
Common errors
| Symptom | Cause |
|---|---|
400 unsupported resolution | Passed unsupported values such as 2k / 4k |
400 This model only supports duration 4-30 seconds, or -1 | duration out of range |
400 first_frame/last_frame tasks only support ratio=adaptive | First/last-frame job with a fixed aspect ratio |
| Async failure (edit / extend style message) | Prompt classified as edit/extend but size / duration violate that type’s rules |
Async failure SensitiveContentDetected | Media or output failed moderation |
Response (submit)
integer
Status code;
200 on successarray
Submit response with
status / task_id표시 Array item
표시 Array item
string
Initially
submittedstring
Task ID for status polling
Completed task (GET /v1/tasks/{task_id})
After submit, poll with Get task status. When status is completed, the payload looks like this.
Completed response example
{
"code": 200,
"data": {
"id": "task_01KZEWTMH6TG3Z1X2QRP2B9ZG9",
"status": "completed",
"progress": 100,
"created": 1786132648,
"completed": 1786132748,
"actual_time": 100,
"estimated_time": 300,
"cost": 0.3104,
"credits_cost": 3.104,
"usage": {
"completion_tokens": 38800
},
"result": {
"videos": [
{
"url": [
"https://cdn.example.com/video/…-video_task_01KZEWTMH6TG3Z1X2QRP2B9ZG9.mp4"
],
"expires_at": 1786219148
}
]
}
}
}
Completed fields
| Field | Type | Description |
|---|---|---|
data.id | string | Task ID |
data.status | string | Always completed when done |
data.progress | int | Always 100 when done |
data.created / data.completed | int | Submit / finish time (Unix seconds) |
data.actual_time | int | Elapsed seconds = completed − created |
data.estimated_time | int | Platform ETA in seconds (reference only) |
data.cost | float | Actual charge in USD for this job (includes discounts; matches billing logs) |
data.credits_cost | float | Credits charged = cost × 10 |
data.usage.completion_tokens | int | Tokens consumed. Settlement: cost = completion_tokens ÷ 10⁶ × token unit price × discount |
data.result.videos[].url | string[] | Video URL(s). This is an array — use url[0]. Values are long-lived platform CDN URLs after re-hosting |
data.result.videos[].expires_at | int | Expiry timestamp (kept for compatibility; re-hosted URLs are long-lived) |
data.result.videos[].last_frame_url | string | Last-frame image (only if submit used return_last_frame=true) |
Notes
- Failed tasks (
status=failed):costis always0(pre-charge fully refunded); reason indata.error.message usagemay be missing for a few seconds after completion (settlement lag); query again shortly
Differences from 2.0
| Feature | 2.0 | 2.5 |
|---|---|---|
| Model | seedance-2.0, etc. | seedance-2.5 |
| Duration | ~4–15s | 4–30s, or -1 auto |
| Resolution | 480p / 720p / 1080p / 4k | 480p / 720p / 1080p |
| Reference images | ≤9 | ≤30 |
| Reference videos | ≤3, total ~<15s | ≤10, total ≤30s |
| Reference audio | ≤3, total ≤15s | ≤10, total ≤30s; audio-only OK |
| Output format | Mainly mp4 | mp4 / mov |
| Watermark | — | watermark |
Private asset:// | Supported | Shared with the same private APIs |