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、動画/音声形式の非公開素材は、審査モデルが動画と音声に対応していないため審査されません。審査呼び出し自体は、動画リクエストを送信したユーザーには課金されません。- 検出時は HTTP 400(
nsfw_content_detected)を同期的に返します。タスクとtask_idは作成されず、動画生成枠も消費されません - 審査サービスが利用できない、タイムアウトする、または応答が不正な場合は fail-open となり、生成リクエストは続行されます。このオプションを絶対的な安全保証として使用しないでください
- 公開画像 URL に解決できない入力はスキップされます
{
"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"
}
}
boolean
true にすると 480p の試作動画を生成します。seedance-2.5 のみ対応。省略時は通常生成になります。resolutionは480pのみ。省略時も480pdraft_task_idと併用不可- 試作動画は作成から 3 日間有効。成功後に 1080p の完成動画を生成可能
string
完成済みの試作動画から 1080p の完成動画を生成します。動画 URL ではなく、試作の送信レスポンスにある APIMart タスク ID(
data[0].task_id)を指定します。seedance-2.5のみ対応。試作と同じモデルを使用- 現在の API Key のユーザーが所有し、成功済みかつ作成から 3 日以内の試作が必要
resolutionは1080pのみ。省略時も1080pdraft: trueと併用不可。prompt、参照素材、長さなどの継承フィールドを再送しないこと
string
通常生成・試作では必須。
draft_task_id で完成動画を生成する場合は送信禁止で、試作のプロンプトを自動継承します。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.試作モードの例外:draft: true は 480p のみ(省略時も同じ)、draft_task_id は 1080p のみ(省略時も同じ)。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).
試作モード
まず 480p の試作動画で映像を確認し、そのタスク ID から 1080p の完成動画を生成します。完成動画は試作のプロンプト、参照素材、長さ、縦横比、seed、音声設定、タスク種別を再利用し、試作の映像に合わせます。
ステップ 1:480p の試作動画を生成
通常の生成リクエストに"draft": true を追加します。素材とタスク種別の制限は同じです。resolution 省略時は 480p、720p や 1080p は 400 になります。
curl -X POST 'https://api.apimart.ai/v1/videos/generations' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "seedance-2.5",
"prompt": "草地に座るキツネ。カメラがゆっくり引き、そよ風が毛を揺らす",
"image_urls": ["https://example.com/reference.png"],
"duration": 5,
"size": "16:9",
"draft": true
}'
data[0].task_id から試作タスク ID を取得し、タスク状態 をポーリングします。data.status が completed になってから完成動画を送信してください。
curl 'https://api.apimart.ai/v1/tasks/task_01KZEVX5R6DM5K9T698P1SDKCR' \
-H 'Authorization: Bearer YOUR_API_KEY'
pending は待機、processing は生成中、completed は成功、failed は失敗です。動画 URL は data.result.videos[].url 配列の url[0] から取得します。
ステップ 2:1080p の完成動画を生成
ステップ 1 の ID をdraft_task_id に指定します。resolution 省略時は 1080p、それ以外は 400 になります。
curl -X POST 'https://api.apimart.ai/v1/videos/generations' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "seedance-2.5",
"draft_task_id": "task_01KZEVX5R6DM5K9T698P1SDKCR",
"output_format": "mov",
"return_last_frame": true,
"watermark": false
}'
GET /v1/tasks/{task_id} で照会します。
次のフィールドは試作から継承します。同じ値でも再送すると 400 になるため、送信しないでください。
prompt, image_urls, image_with_roles, video_urls, audio_urls, duration, size, aspect_ratio, seed, generate_audio, audio, omni_reference_task_type, generation_type, camerafixed, web_search, tools.
次の出力オプションは変更できます。
| パラメータ | 説明 |
|---|---|
output_format | mp4(既定)または mov |
return_last_frame | 最終フレーム画像を返すか。省略時は試作設定ではなくモデルの既定値 |
watermark | 透かしを付けるか。省略時は試作設定ではなくモデルの既定値 |
draft: true と draft_task_id は排他的です。試作・完成動画とも service_tier は非対応です。試作は作成から 3 日間有効です。タスクが存在しない、別ユーザー所有、未成功、試作ではない、期限切れの場合は、完成動画の送信時に 400 となり、タスク作成・課金は行いません。draft_task_id で後から再試行してください。
有効期限内の試作から完成動画を複数回生成できます。それぞれ独立したタスクとして個別に課金されます。
試作モードの料金
試作は通常の 480p 動画として課金します。参照動画の入力時間も通常どおり含み、合計最大 30 秒です。 完成動画は 1080p で課金されます。ステップ 1 に元の参照動画が含まれていた場合は1080P-input、含まれていなかった場合は通常の 1080P の料金区分を選択し、その区分のトークン単価で精算します。
完成動画の課金対象となる入力秒数は、ステップ 1 で使用した元の参照動画の合計時間で、最大 30 秒です。生成された Draft 動画自体は動画入力に含めません。 完成動画の POST は引き続き draft_task_id を参照し、参照素材やその他の継承フィールドを再送してはいけません。素材の再送が不要でも、元の参照動画の時間は課金計算に含まれます。
例えば、ステップ 1 で 22 秒の元の参照動画を使って 11 秒の出力を指定した場合、完成動画のトークン数は 11 + 22 = 33 秒と 1080P-input 区分のトークン単価で見積もります。
| 試作の長さ設定 | 試作の事前引き落とし | 完成動画の事前引き落とし |
|---|---|---|
| 4~30 秒を明示 | 指定時間の 480p。参照動画は通常どおり加算 | 同じ出力時間にステップ 1 の元の参照動画時間を加え、該当する 1080p 区分で計算 |
duration: -1、または edit で長さ省略により -1 に設定 | 出力最大 30 秒。参照動画は通常どおり加算 | 最大 30 秒の出力にステップ 1 の元の参照動画時間を加え、該当する 1080p 区分で計算 |
その他で duration を省略 | 出力 5 秒。参照動画は通常どおり加算 | 5 秒の出力にステップ 1 の元の参照動画時間を加え、該当する 1080p 区分で計算 |
試作トークン数 = (入力動画秒数 + 出力秒数) × 幅 × 高さ × 24 ÷ 1024
完成動画の推定トークン数 = (ステップ 1 の元の参照動画秒数 + 完成動画の出力秒数) × 幅 × 高さ × 24 ÷ 1024
data.usage.completion_tokens で精算トークン数を確認できます。
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 |