Video Generation API (Doubao Seedance)
Last updated: October 23, 2026 (Asia/Shanghai)
Related: Help Center · LLM API · Image Generation · Full Reference
TokenExplore provides two integration protocols for Seedance:
- Seedance official protocol: the most complete set of parameters, with multimodal references, 2.5 editing/extension, asset library references, and signed callbacks; prefer it for new projects.
- Video-compatible protocol: compatible with existing OpenAI video clients; supports common fields such as
prompt,images,seconds, andmetadata.
Both protocols share the same API key, account quota, and billing system, but their request fields, response structures, and task states differ. You must use the same protocol for creation, querying, and status checks; do not mix them.
The API gateway for all requests is https://ai.afp.net. The examples use the following environment variables:
export CIYUAN_BASE_URL="https://ai.afp.net"
export CIYUAN_API_KEY="sk-xxxxxxxx" # Create under "Token Management" in the consoleAuthentication uses the Authorization: Bearer sk-xxx header for all requests. Queries, downloads, and asset operations must use a token from the same account.
Keep your API key safe
An API key is a paid credential. Store it only in server-side environment variables or a secrets manager; never put it in frontend code, screenshots, logs, or public repositories.
1. Models and Endpoints
1.1 Models
| Model ID | Notes |
|---|---|
doubao-seedance-2-5-260628 | Seedance 2.5, quality-first; supports 4–30 seconds and omni-modal reference/editing |
doubao-seedance-2-0-260128 | Seedance 2.0 standard edition; supports 4–15 seconds |
doubao-seedance-2-0-fast-260128 | Seedance 2.0 Fast, speed-first; generally 480p/720p only |
doubao-seedance-2-0-mini-260615 | Seedance 2.0 Mini, lightweight and low-cost; generally 480p/720p only |
Whether a model is available to the current token depends on the token group and channel configuration. Check first:
curl "$CIYUAN_BASE_URL/v1/models" \
-H "Authorization: Bearer $CIYUAN_API_KEY"Do not call model IDs that are not in the returned list. Pricing and available resolutions are subject to "Model Marketplace / Pricing" in the console.
1.2 Endpoint Overview
| Protocol | Create task | Query task | Download result | Main request fields |
|---|---|---|---|---|
| Seedance official (recommended) | POST /api/v3/contents/generations/tasks | GET /api/v3/contents/generations/tasks/{task_id} | content.video_url, or GET /v1/videos/{task_id}/content | content, integer duration, ratio |
| Video-compatible | POST /v1/video/generations (also supports OpenAI Videos style POST /v1/videos) | GET /v1/video/generations/{task_id} (OpenAI Videos style uses GET /v1/videos/{id}) | GET /v1/videos/{task_id}/content | prompt, images, string seconds, metadata |
The official protocol also provides task listing and deletion:
GET /api/v3/contents/generations/tasks?page_num=1&page_size=10
DELETE /api/v3/contents/generations/tasks/{task_id}The list supports filter.status, filter.model, filter.service_tier, and repeated filter.task_ids; page_num and page_size range from 1 to 500 (defaults: 1 / 10). Deleting a queued task cancels it; deleting a finished task only removes the record; deleting a running task returns 409 task_cannot_be_cancelled.
The two protocols' endpoints and fields cannot be mixed
The official endpoint accepts only official fields such as content; the video-compatible endpoint accepts only fields such as prompt / images / seconds / metadata. Sending content to the video-compatible endpoint, or prompt to the official endpoint, will not work with the semantics you expect. The response structures and status enums also differ between the two protocols, so do not force the same parsing code onto both.
2. Seedance Official Protocol
2.1 Create a Task
The following example generates a 4-second, 480p, 16:9 video without audio, suitable for validating the pipeline first:
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-20261023-001" \
-d '{
"model": "doubao-seedance-2-5-260628",
"content": [
{"type": "text", "text": "An orange cat watching the rain by the window, slow push-in, cinematic lighting"}
],
"duration": 4,
"resolution": "480p",
"ratio": "16:9",
"generate_audio": false
}'A successful creation only means the platform has accepted the task; it returns a public task ID:
{"id": "task_xxxxxxxxx"}- The task ID is generated by the platform, not the upstream task ID; do not concatenate it onto an upstream URL.
Idempotency-Keyprevents duplicate tasks and duplicate charges caused by client timeout retries: reuse the same value for the same business submission and use a new value for a new generation intent. The same key with a different request returns409 idempotency_conflict.- The official create request body is limited to 64 MiB (about 64 MB); for large assets, use the asset library or a public HTTPS URL.
- The legacy prefix
/doubao/api/v3/contents/generations/tasksremains available as a compatibility entry point. For new projects, use/api/v3/contents/generations/tasks, and do not mix the two prefixes for queries.
2.2 Query a Task
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks/task_xxxxxxxxx" \
-H "Authorization: Bearer $CIYUAN_API_KEY"| Status | Meaning | Action |
|---|---|---|
queued | Accepted, waiting for generation | Keep polling |
running | Upstream generation in progress | Keep polling |
succeeded | Generation succeeded | Read content.video_url |
failed | Failed | Read error, adjust, and retry |
cancelled | Cancelled | Stop polling |
expired | Task record has expired | Submit again |
Successful response example:
{
"id": "task_xxxxxxxxx",
"model": "doubao-seedance-2-5-260628",
"status": "succeeded",
"content": {
"video_url": "https://example.com/result.mp4",
"video_asset_id": "asset_xxxxxxxxx"
},
"usage": {"completion_tokens": 38830, "total_tokens": 38830},
"created_at": 1787827200,
"updated_at": 1787827300
}- The final cost is settled based on
usage.total_tokens. - Once result archiving is enabled on the platform,
content.video_asset_idmeans the result has been archived to the current account's asset library; archiving may finish slightly later than the terminal generation state—if it does not appear immediately, query again later. - Failed tasks are refunded asynchronously after backend confirmation, but a successful submission does not mean the video was generated successfully; always rely on the task status.
2.3 Content Types and Asset Roles
content is an ordered array that describes the prompt and reference assets in order:
type | Accepted sources | Available role |
|---|---|---|
text | UTF-8 text | None |
image_url | Public https, image data URL, asset:// asset | first_frame, last_frame, reference_image |
video_url | Public https, asset:// asset (Base64 not supported) | reference_video |
audio_url | Public https, audio data URL, asset:// asset | reference_audio |
draft_task | A task_xxx accessible to the current account | None |
{"type":"image_url","image_url":{"url":"https://example.com/first-frame.png"},"role":"first_frame"}roleandtypeare at the same level; one element can express only one content type.asset://can reference only assets owned by the current user with a valid status; if asset referencing is not enabled, it returnsasset input is not enabled.- The official endpoint rejects unknown top-level fields and unknown fields inside content with
400 invalid_request; field names must match the documentation exactly.
2.4 Generation Parameters
| Parameter | Required | Notes |
|---|---|---|
model | Yes | Use a model ID from Section 1 |
content | Yes | Ordered content array; must contain at least one content element |
duration | No | 2.0: -1 or 4–15; 2.5: -1 or 4–30 |
resolution | No | e.g. 480p, 720p; higher resolutions depend on the model and channel |
ratio | No | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptive |
generate_audio | No | Whether to generate audio |
omni_reference_task_type | No | 2.5 only: auto, reference, edit, extend |
callback_url | No | Callback URL for terminal task states; requires callback capability to be enabled on the platform, and must be a public http(s) address |
return_last_frame | No | Return the last frame; once result archiving is enabled on the platform, last_frame_url / last_frame_asset_id may appear in successful responses |
execution_expires_after | No | Task execution expiry in seconds, range 3600–259200 |
seed / watermark / camera_fixed | No | Random seed / watermark / fixed camera |
draft / frames / tools / output_format / service_tier / priority / safety_identifier | No | Advanced parameters; whether they take effect depends on the model and channel |
- Before charging and submitting to upstream, the platform validates the combination of duration, ratio, and 2.5 task type; unsupported combinations return
400 unsupported_parameter_combination. ratioaccepts only standard values; after successful generation, the actual ratio returned by upstream may be a fraction such as427:240. Store it as a string and do not force-stretch it to16:9.- Resolution, model capabilities, and billing tiers are subject to the console model description and your bill.
2.5 Video Reference and Editing (Seedance 2.5)
Use omni_reference_task_type to declare an omni-modal reference subtask (for a Seedance 2.5 first-frame task, if ratio is passed explicitly it must be adaptive); there is no edit: true field:
| Scenario | omni_reference_task_type | Parameter requirements |
|---|---|---|
| Regenerate with reference motion/style/camera | reference | At least one reference asset; regular ratio and duration |
| Modify the visuals or audio of a reference video | edit | At least one reference_video; ratio=adaptive; duration=-1 |
| Extend a reference video | extend | At least one reference_video; ratio=adaptive |
| Let the model decide automatically | auto or omitted | When a reference video is included, the platform requires adaptive and -1 |
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "doubao-seedance-2-5-260628",
"content": [
{"type": "text", "text": "Change the jacket of the person in the reference video to red, keeping the original motion, camera movement, and audio"},
{"type": "video_url", "video_url": {"url": "https://example.com/source.mp4"}, "role": "reference_video"}
],
"duration": -1,
"ratio": "adaptive",
"omni_reference_task_type": "edit"
}'If you need a fixed output ratio or duration, pass reference explicitly; the prompt should clearly state what to modify and what must be preserved (motion, camera, and audio).
2.6 Query, List, and Delete
To query a single task, see §2.2. List and delete examples:
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks?page_num=1&page_size=10&filter.status=succeeded" \
-H "Authorization: Bearer $CIYUAN_API_KEY"
curl -X DELETE "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks/task_xxxxxxxxx" \
-H "Authorization: Bearer $CIYUAN_API_KEY"- The list returns
{"items": [...], "total": N}, sorted bycreated_atin descending order. - Available
filter.statusvalues match the task states:queued,running,succeeded,failed,cancelled,expired. - A successful deletion returns
204 No Content: queued tasks are cancelled; finished tasks have their upstream task deleted first, then the platform record soft-deleted; running tasks return409 task_cannot_be_cancelled, and already-cancelled tasks return409 task_already_cancelled. - Task IDs are visible only to the account that created them; you cannot query or delete another user's tasks.
2.7 Download the Result
After a task succeeds, prefer reading content.video_url. Upstream URLs may expire, so download or transfer the file as soon as possible; you can also have the platform proxy the download using the same token:
curl -L "$CIYUAN_BASE_URL/v1/videos/<task_id>/content" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-o output.mp4This endpoint supports Range for resumable downloads; call it only after the task succeeds (official succeeded / OpenAI Videos style completed).
2.8 Signed Callbacks
When creating an official task, pass callback_url (callback capability must be enabled on the platform). After the task reaches a terminal state (succeeded / failed / cancelled / expired), the platform sends an HTTP POST to that address:
| Header | Purpose |
|---|---|
X-Seedance-Event-Id | Unique event ID; receivers should deduplicate on this field |
X-Seedance-Timestamp | Signature timestamp (Unix seconds) |
X-Seedance-Signature | HMAC-SHA256 signature in v1=<hex> format |
The signed payload is timestamp + "." + raw_body. The API key used when creating the task is currently used as the signing secret. You must verify the signature against the raw request body you received; do not re-serialize the JSON before computing it.
import crypto from 'node:crypto'
export function verifySeedanceWebhook(rawBody, headers, signingSecret) {
const timestamp = headers['x-seedance-timestamp']
const received = headers['x-seedance-signature']
const expected = 'v1=' + crypto
.createHmac('sha256', signingSecret)
.update(timestamp + '.' + rawBody)
.digest('hex')
return typeof received === 'string' &&
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))
}- The callback body contains
id,type,created_at, anddata;typeiscontent_generation.task.{status}, anddatais the task snapshot, with fields similar to the official task query response; archiving-related fields may only be filled in on query. - The platform uses at-least-once delivery semantics; handle events idempotently by
X-Seedance-Event-Id, and return 2xx as soon as possible after verifying the signature and persisting the event. - If you don't need event notifications, polling is sufficient; polling and callbacks can be enabled at the same time.
3. Video-Compatible Protocol
The video-compatible protocol is intended for existing OpenAI video clients or unified task wrappers. It is an additional compatibility layer provided by the platform, not the Seedance official protocol.
3.1 Endpoints and How to Choose
| Operation | Legacy compatibility entry | OpenAI Videos style |
|---|---|---|
| Create task | POST /v1/video/generations | POST /v1/videos |
| Query task | GET /v1/video/generations/{task_id} | GET /v1/videos/{id} |
| Download result | GET /v1/videos/{task_id}/content | Same as left |
The two entries return different response structures (see §3.4); use one entry consistently for creation and querying, and do not mix them within a single flow. Only the OpenAI Videos style entry uses queued / in_progress / completed / failed, where completed corresponds to the official protocol's succeeded; the legacy compatibility entry returns internal platform states (such as IN_PROGRESS / SUCCESS / FAILURE), so do not use completed to determine terminal states.
3.2 Create a Task
curl "$CIYUAN_BASE_URL/v1/video/generations" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "doubao-seedance-2-5-260628",
"prompt": "Sunrise over the sea, slow push-in, waves gently lapping the rocks, cinematic",
"seconds": "4",
"metadata": {
"resolution": "480p",
"ratio": "16:9",
"generate_audio": false
}
}'Successful creation response example (legacy compatibility entry):
{
"id": "task_xxxxxxxxx",
"task_id": "task_xxxxxxxxx",
"status": "queued",
"model": "doubao-seedance-2-5-260628",
"created_at": 1787827200
}If you use the OpenAI Videos style entry, the creation response is a video object (with no task_id):
{
"id": "task_xxxxxxxxx",
"object": "video",
"model": "doubao-seedance-2-5-260628",
"status": "queued",
"progress": 0,
"created_at": 1787827200
}A successful creation only means the task has been accepted; the response does not contain a video URL.
3.3 Request Parameters
| Field | Notes |
|---|---|
model | Required; model ID |
prompt | Required; the prompt |
images | Array of reference image URLs. The OpenAI Videos style path accepts only images; do not pass a single image |
image | Single image URL supported by the legacy compatibility entry (converted to images internally); new code should use images consistently |
seconds | Duration as a string, e.g. "4", "-1"; takes precedence over duration when both are present |
duration | Duration as an integer. The OpenAI Videos style entry can use it instead of seconds; the legacy compatibility entry reads only seconds and ignores duration |
metadata | Passes through official parameters: content, resolution, ratio, generate_audio, omni_reference_task_type, etc. |
- Parameters such as
resolution,ratio, andgenerate_audiomust be placed insidemetadata; they are ignored at the top level. - Put reference images, videos, or audio in
metadata.content, nottext; write the prompt inprompt. If you need a first-framerole, explicitly writeimage_url+role: "first_frame"inmetadata.content. - The compatibility protocol does not support binary file uploads; assets must be public URLs. To reuse assets, use the official protocol + asset library.
- A top-level
contentdoes not cause the compatibility endpoint to return a parameter error; it is simply ignored. For multimodal references, put them inmetadata.contentor switch to the official protocol.
3.4 Query Status and Download
The OpenAI Videos style entry returns a video object with status queued → in_progress → completed (or failed):
curl "$CIYUAN_BASE_URL/v1/videos/task_xxxxxxxxx" \
-H "Authorization: Bearer $CIYUAN_API_KEY"{
"id": "task_xxxxxxxxx",
"object": "video",
"model": "doubao-seedance-2-5-260628",
"status": "completed",
"progress": 100,
"created_at": 1787827200,
"completed_at": 1787827300
}The legacy compatibility entry returns a generic task structure, with the result URL in data.result_url (the field may not exist; rely on the download endpoint):
curl "$CIYUAN_BASE_URL/v1/video/generations/task_xxxxxxxxx" \
-H "Authorization: Bearer $CIYUAN_API_KEY"{
"code": "success",
"message": "",
"data": {
"task_id": "task_xxxxxxxxx",
"status": "IN_PROGRESS",
"progress": "60%"
}
}Don't look for the result URL in the query response
The /v1/videos/{task_id} response does not contain metadata.url, task_id, or a video URL; for the legacy compatibility entry, the result URL is in data.result_url, and that field may not exist. Always download via GET /v1/videos/{task_id}/content.
curl -L "$CIYUAN_BASE_URL/v1/videos/task_xxxxxxxxx/content" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-o output.mp4This endpoint supports Range for resumable downloads; downloads must use a token from the same account that created the task (any valid token on that account works).
3.5 Recommendations
- For new projects, or when you need first/last frames, reference audio/video, 2.5 editing/extension, or asset library reuse, use the Seedance official protocol.
- If you already have OpenAI video tools and only need text-to-video/image-to-video, use the video-compatible protocol; if you find that a parameter is not taking effect, switch to the official protocol.
- Whichever protocol you choose, production systems should store
task_xxx, the model, key generation parameters, and error messages, to make it easier to verify status, billing, and retries.
4. Asset Library (Official Assets API)
The asset library is used to first import reference images, reference videos, and reference audio into the platform, then reference them repeatedly in official-protocol tasks via asset://<asset ID>. It suits scenarios where the same asset is used many times, or where upstream cannot fetch external links directly.
Assets and groups belong to the current user; other users cannot view, modify, delete, or reference your assets via asset://.
The asset library uses the Action style of the Volcengine Assets API: all operations POST to a fixed path, with Action and Version in the query parameters. Do not build Actions into ordinary REST paths (such as /api/v3/assets/CreateAsset), or you will get a 404.
POST https://ai.afp.net/api/v3/assets?Action=<Action>&Version=2024-01-01
Authorization: Bearer sk-xxx
Content-Type: application/jsonTwelve Actions are currently supported:
| Category | Action |
|---|---|
| Groups | CreateAssetGroup, ListAssetGroups, GetAssetGroup, UpdateAssetGroup, DeleteAssetGroup |
| Assets | CreateAsset, ListAssets, GetAsset, UpdateAsset, DeleteAsset |
| Real-person verification | CreateVisualValidateSession, GetVisualValidateResult |
Version must be 2024-01-01; an unsupported Action returns InvalidAction, and an incorrect version returns InvalidVersion. Responses are uniformly wrapped in ResponseMetadata, with business data in Result and errors in ResponseMetadata.Error. The real-person verification capability is not currently connected to upstream; when all parameters are present, it returns OperationDenied.CapabilityNotSupported.
4.1 Create a Group and Import Assets
curl "$CIYUAN_BASE_URL/api/v3/assets?Action=CreateAssetGroup&Version=2024-01-01" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"Name":"Project assets","GroupType":"AIGC","ProjectName":"default"}'
curl "$CIYUAN_BASE_URL/api/v3/assets?Action=CreateAsset&Version=2024-01-01" \
-H "Authorization: Bearer $CIYUAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"GroupId":"<group ID returned by the previous step>",
"Name":"First frame",
"AssetType":"Image",
"URL":"https://example.com/first-frame.png",
"ProjectName":"default"
}'CreateAssetGroup response example:
{
"ResponseMetadata": {"RequestId": "req-xxxxxxxx", "Action": "CreateAssetGroup", "Version": "2024-01-01", "Service": "ark", "Region": "cn-beijing"},
"Result": {"Id": "group-xxxxxxxx"}
}CreateAssetreturnsResult.Id(the asset ID).AssetTypecan only beImage,Video, orAudio, and must match the actual media type of the URL.GroupTypecurrently supports onlyAIGC; whenProjectNameis omitted it defaults todefault, with a maximum length of 64 bytes (UTF-8).URLmust be a public http(s) address accessible to the platform; the platform performs SSRF validation, andlocalhostand private network addresses are rejected.
4.2 Reference Assets in Generation Tasks
After importing an asset, use asset://<asset ID> instead of a URL in the official protocol's content:
{"type":"image_url","image_url":{"url":"asset://asset_xxxxxxxx"},"role":"first_frame"}asset://requires the platform's asset referencing capability to be enabled; when it is not enabled, it returnsasset input is not enabled, in which case use a public http(s) URL instead.- The asset type must match the content item (image for
image_url, video forvideo_url, audio foraudio_url). - Tasks that reference assets must use a token from the same account that imported the assets.
4.3 Manage Assets (REST / Console)
In addition to the Action API, the platform also provides internal REST endpoints used by the console and automation tools:
POST /api/v3/assets Upload a file or import from a public URL
GET /api/v3/assets Paginate, search, and filter assets
GET /api/v3/assets/{asset_id} Asset details
PATCH /api/v3/assets/{asset_id} Rename or change group
DELETE /api/v3/assets/{asset_id} Delete asset
GET /api/v3/assets/{asset_id}/content Download / probe file (supports Range)
HEAD /api/v3/assets/{asset_id}/content Probe file
POST /api/v3/assets/{asset_id}/prepare Prepare/register an upstream asset for a model (request body must include model)
POST /api/v3/assets/from-task Archive a task result as an asset
POST /api/v3/asset-groups Create group
GET /api/v3/asset-groups List groups
GET /api/v3/asset-groups/{group_id} Group details
PATCH /api/v3/asset-groups/{group_id} Rename group
DELETE /api/v3/asset-groups/{group_id} Delete group
Legacy paths /api/media/assets and /api/media/asset-groups are still retained.- REST endpoints accept both the console login session and an API key; for automated programs, use
Authorization: Bearer sk-xxx. - The
/api/media/assetslist supportspage_num,page_size,q,kind, andgroup_idparameters; the upload endpoint supports multipart files or public URL import viaurl. - The console's "Asset Library" supports upload, preview, download, copying
asset://references, editing names/groups, and deletion; the list can be filtered by name, type, and group. - The per-file limit is 512 MB; the platform validates the actual MIME type and stores a SHA-256.
- Asset library permissions are divided into view, upload, manage, delete, and archive; without permission, buttons are hidden or requests return
403.
4.4 Retention, Isolation, and Upstream Binding
- Group records are retained long-term until explicitly deleted;
DeleteAssetGrouprequires that the group contain no unexpired assets, otherwise it returnsOperationDenied.AssetGroupNotEmpty. - Platform assets are retained for 7 days by default, and the deployer can configure long-term retention.
expires_atin asset management APIs or the console is a Unix timestamp in seconds; after expiry, assets no longer appear in lists and cannot be used for generation tasks. Expiry cleanup deletes only platform metadata; the underlying objects are reclaimed by object storage (S3 / Tencent COS-compatible) lifecycle rules. - Assets and groups are isolated by user +
ProjectName; other users cannot query or reuse them; the default project name isdefault. - Platform assets are stored only in TokenExplore and are not synced upstream. When routing a task, the platform first checks whether candidate channels support the required image/video/audio capability; after selecting a channel, it registers a temporary upstream asset on demand for that task.
- Upstream bindings are single-use by default, and upstream may delete them after the task ends; even if reuse is configured, the TTL will not exceed the upstream retention period. Upstreams that only support fetching URLs use the platform's short-lived URL directly. As a result, assets are not pre-bound to any upstream, and you can switch freely between channels.
- Capabilities such as virtual assets, private real-person assets, real-person authentication, and update/delete are configured by administrators per channel; the current upstream does not support private real-person assets, and the related Actions return
OperationDenied.CapabilityNotSupportedrather than404. - The
URLreturned byGetAsset/ListAssetsis a temporary address issued by the platform (1 hour by default) and must not be stored as a permanent external link. - Assets referenced by in-progress tasks cannot be deleted; attempting to do so returns
OperationDenied.AssetInUse.
5. Async Flow, Polling, and Billing
Submitting a task only means it has been enqueued. Recommended flow:
- Submit and save the returned task ID and the full request parameters (for the official protocol, include
Idempotency-Key). - Query every 5 seconds, backing off gradually to 15–30 seconds; avoid high-frequency polling.
- Download once the task reaches a successful terminal state (official
succeeded/ OpenAI Videos stylecompleted); forfailed, readerrorand stop retrying. - A status of
expiredmeans the record has expired (the upstream record may no longer be queryable), and you need to submit again; result URLs expire, so download promptly after success.
Python polling example (official protocol):
import os, time, requests
BASE = os.environ["CIYUAN_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {os.environ['CIYUAN_API_KEY']}"}
created = requests.post(f"{BASE}/api/v3/contents/generations/tasks", headers=HEADERS, json={
"model": "doubao-seedance-2-5-260628",
"content": [{"type": "text", "text": "An orange cat watching the rain by the window, slow push-in"}],
"duration": 4, "resolution": "480p", "ratio": "16:9", "generate_audio": False,
})
created.raise_for_status()
task_id = created.json()["id"]
print("task:", task_id)
delay = 5
while True:
info = requests.get(
f"{BASE}/api/v3/contents/generations/tasks/{task_id}", headers=HEADERS
).json()
status = info.get("status")
print("status:", status)
if status == "succeeded":
url = info["content"]["video_url"]
break
if status in ("failed", "cancelled", "expired"):
raise RuntimeError(info.get("error") or status)
time.sleep(delay)
delay = min(delay * 1.5, 30)
video = requests.get(url, timeout=120)
video.raise_for_status()
open("output.mp4", "wb").write(video.content)
print("saved output.mp4")Billing is calculated from the upstream-returned usage.total_tokens along with the model, input type, and resolution; a hold may be placed at submission time, and failed tasks are refunded asynchronously. The final amount is subject to the console bill.
6. Common Errors and Troubleshooting
| Error | Common cause | Handling |
|---|---|---|
401 Unauthorized | Invalid or expired key, or missing request header | Check the Bearer header and key status |
No available channel for model | Model not enabled, channel not enabled, or group lacks permission | Check /v1/models first |
503 channel_not_available | The official protocol cannot find a Seedance-compatible channel | Check channel configuration and group |
400 invalid_request | Missing content, malformed JSON, unknown field, asset input is not enabled | Check field names and types |
400 unsupported_parameter_combination | Unsupported combination of duration, ratio, and task type | Adjust per 2.4 / 2.5 |
403 OperationDenied.CapabilityNotSupported | Asset library not enabled at all (Action requests) | Contact an administrator to enable asset library capability |
400 OperationDenied.CapabilityNotSupported | The current upstream does not support the asset/capability (e.g. private real-person) | Use a supported asset type or channel |
404 not_found | Official task API not enabled, or asset library REST routes not enabled | Confirm the platform has enabled the corresponding capability |
413 asset_too_large | Uploaded file exceeds 512 MB | Compress the asset or use a public URL |
asset_not_found / asset_not_active (REST management API) | Asset deleted, owned by someone else, or not yet available | Go back to the asset library to confirm and re-copy the reference |
invalid_asset / asset_not_supported (task referencing an asset) | asset:// type mismatch, asset unavailable, or the current channel does not support it | Check asset ownership/type, or switch to a channel that supports the capability |
409 task_cannot_be_cancelled | Running tasks cannot be cancelled | Wait for the terminal state or stop polling |
Stuck in queued | Upstream queueing or channel switching | Keep polling; retry after your business timeout |
Task failed | Parameters, content moderation, or upstream error | Save error, adjust, and resubmit |
| Result URL unavailable | Task not finished or URL expired | Confirm the success status; download promptly or proxy via the content endpoint |
| Callback signature mismatch | Request body re-serialized, wrong secret, or timestamp not the original value | Compute the HMAC from the raw body + timestamp, and check the v1= prefix |
Official protocol or video-compatible: which should I choose?
Use the official protocol when you need first/last frames, reference audio/video, 2.5 editing/extension, the asset library, or signed callbacks; use the compatibility protocol when you already have OpenAI video tools and only need text-to-video/image-to-video. The endpoints and fields of the two protocols cannot be mixed.
Previous: Image Generation · Back to: Help Center