Generate Videos with Seedance
What you can do
Use WorldRouter’s native async task API for text-to-video, video-to-video, and image-guided Seedance generation.
Before you start
Seedance uses WorldRouter’s native async task API. Create a task, then check its status until the video is ready.
- Send text-only and reference-video requests directly.
- Upload reference images first, then use the returned asset URL in your request.
Task routes
POST /api/v3/contents/generations/tasksGET /api/v3/contents/generations/tasks/{task_id}
Asset helper routes
Use these routes only for reference-image uploads:
POST /v1/asset-groupsPOST /v1/asset-groups/{asset_group_id}/assets
Start from Quickstart if you still need an API key or the
base URL. Use the same origin shown there: https://inference-api-pre-d80ca3.worldrouter.ai. Seedance task
routes append /api/v3/... and are not part of the OpenAI-compatible
/v1/videos surface, so do not nest them under /v1.
Quick start flow
The asset upload step depends on what kind of reference you pass:
- Text-only or with a video reference: skip the asset step. Send the request directly.
- Seedance with a public image reference URL: send the public URL directly with a basic Seedance model.
- Seedance with uploaded assets: use a Seedance asset model and create the asset group with
provider: "byteplus_official". - Portrait Library references: create a reusable
portrait://...asset once, then prepare its Seedance binding before using it with a Seedance asset model. Direct API requests also require a ready BytePlus binding.
- 1If you use a basic Seedance model with a public image URL, skip the asset step. For uploaded assets, create an asset group with
provider: "byteplus_official"and upload the image. - 2Before using a Portrait Library reference, prepare its Seedance binding. In Playground, prepare the portrait in Portrait Library; direct API requests can use the binding route below.
- 3Create a Seedance task with
POST /api/v3/contents/generations/tasks. - 4Check task status with
GET /api/v3/contents/generations/tasks/{task_id}until the job reaches a terminal state. - 5Read
content.video_urlfrom the task response and download the generated video from that URL.
Supported request models
These are the request model names you should send in the model field:
| Model | Upstream | Best for |
|---|---|---|
seedance-2.0 | BytePlus | Standard text-to-video. |
seedance-2.0-fast | BytePlus | Faster iterations. |
seedance-2.5 | BytePlus | Seedance 2.5 text-to-video. |
seedance-2.5-asset | BytePlus | Seedance 2.5 asset-reference video. |
seedance-2.0-asset | BytePlus | Asset-reference video. |
seedance-2.0-asset-fast | BytePlus | Faster asset-reference video. |
These unqualified IDs are the public model names shown in the model catalog and
Playground. The previous *-official request IDs remain accepted as
backward-compatible aliases; use the names in the table for new integrations.
New Seedance tasks and asset operations use BytePlus. Existing Relay task IDs
remain pollable and settle at their historical rates, but Relay is not a
currently offered Seedance provider.
Important behavior:
For text-only generation or reference-video generation, send your request directly with one of the basic model names above.
If you are using a reference image:
- Basic Seedance models can use public image URLs directly.
- Seedance asset models use the asset helper routes with
provider: "byteplus_official", then use the returnedasset://...URL withseedance-2.0-asset,seedance-2.0-asset-fast, orseedance-2.5-asset. Thebyteplus_officialvalue is the asset API’s provider enum. - Seedance 2.5 supports
480p,720p, and1080poutputs. Duration may be-1for automatic duration or an integer from4through30. It does not acceptcamera_fixed. - Seedance 2.5 also accepts
output_format,generate_audio,return_last_frame,priority,execution_expires_after, andcallback_url.
When you use an uploaded image asset, use one of the Seedance asset model names.
Text-to-video
Start here if you want the simplest Seedance workflow.
This example shows the basic text-to-video flow: send a prompt, create a task, then check its progress until the video is ready.
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/api/v3/contents/generations/tasks" \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0",
"content": [
{
"type": "text",
"text": "A cinematic video of a city street at sunset."
}
],
"resolution": "720p",
"duration": 5
}'You can start with this example as-is, then adjust the parts that matter most for your use case:
model: choose a standard or faster Seedance generation path.text: describe the subject, style, setting, and motion you want.resolution: choose the output quality supported by the model.duration: choose how long the generated video should be.
Typical create response:
{
"id": "task-123",
"requestId": "req-123"
}This response confirms that the task was created successfully. Your video is not ready yet.
Save the returned task id, then continue to Check task status.
Check task status
All Seedance requests follow the same async flow after task creation, including text-to-video, reference-video, and reference-image requests.
Use the task id returned from the create response to check whether the video is still running, has succeeded, or has failed.
curl "https://inference-api-pre-d80ca3.worldrouter.ai/api/v3/contents/generations/tasks/task-123" \
-H "Authorization: Bearer your_api_key"Typical status response:
{
"id": "task-123",
"model": "seedance-2.0",
"status": "succeeded",
"content": {
"video_url": "https://media.example.com/seedance/output.mp4"
},
"resolution": "720p",
"duration": 5,
"usage": {
"output_tokens": 7522
}
}When status becomes succeeded, use content.video_url to download the final video.
WorldRouter normalizes upstream task states into:
queuedrunningsucceededfailedcancelledexpired
A failed task also carries an error object with the upstream code and a
bounded message. When the failure is one WorldRouter can explain, the object
adds a guidance field describing what to change.
Use a reference video
Reference videos can be sent directly in the request. Unlike image references, they do not require the asset helper flow.
{
"model": "seedance-2.0",
"content": [
{
"type": "text",
"text": "Keep the motion rhythm of the input video and restyle it into a cinematic tea scene."
},
{
"type": "video_url",
"role": "reference_video",
"video_url": {
"url": "https://example.com/input.mp4"
}
}
],
"resolution": "720p",
"duration": 5
}You can customize the same core fields here as well:
text: describe the style or transformation you want.video_url: provide the reference video.resolution: choose the output quality supported by the model.duration: choose the target output length.
After submitting the request, follow the same steps in Check task status to monitor the task and download the result.
Asset flow for image references
Basic Seedance models can use public image URLs directly. Use the asset flow below when you want uploaded assets with seedance-2.0-asset, seedance-2.0-asset-fast, or seedance-2.5-asset.
Portrait Library
Portrait Library is WorldRouter’s reusable character asset layer. Seedance
asset models use virtual portraits in later video requests.
Portrait creation stores a generic WorldRouter asset and does not create a
Seedance provider asset immediately. Prepare the Seedance binding in Portrait
Library before using the portrait with an asset model in Playground.
Playground reads the ready binding and submits its asset://... reference to
the inference task route. Direct API requests also require a ready BytePlus
binding before the portrait can be used. Relay bindings are not available for
new materialization.
The first supported portrait type is virtual, for AI-generated or otherwise
non-real-human characters. Real-human portraits require provider verification
and are intentionally rejected by this route until the provider verification
flow is enabled.
Portrait images are stored in WorldRouter object storage. Local uploads are
copied directly into the durable portrait prefix; URL imports are fetched once,
copied into the same storage, and no longer depend on the original host for
later previews or provider materialization.
Create a virtual portrait from a local image:
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/v1/portraits" \
-H "Authorization: Bearer your_api_key" \
-H "Idempotency-Key: portrait-upload-luna-1" \
-F "name=Luna" \
-F "kind=virtual" \
-F "description=AI-generated character reference" \
-F "image=@./luna.png"You can also import a portrait from an HTTP(S) image URL:
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/v1/portraits" \
-H "Authorization: Bearer your_api_key" \
-H "Idempotency-Key: portrait-create-luna-1" \
-H "Content-Type: application/json" \
-d '{
"name": "Luna",
"kind": "virtual",
"image_url": "https://example.com/luna.png",
"description": "AI-generated character reference"
}'If you call the backend directly, prepare the Seedance binding before
submitting the asset generation request. Use provider: "byteplus_official":
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/v1/portraits/portrait_123/bindings/seedance" \
-H "Authorization: Bearer your_api_key" \
-H "Idempotency-Key: portrait-binding-seedance-1" \
-H "Content-Type: application/json" \
-d '{
"provider": "byteplus_official"
}'Once the binding is ready, use the returned asset_url or the portrait://...
reference in the matching asset generation request. The backend resolves a ready
portrait reference to asset://.... Playground also converts a ready Seedance
portrait reference before submitting the task:
{
"model": "seedance-2.0-asset",
"content": [
{
"type": "text",
"text": "Luna walks through a sunlit city street."
},
{
"type": "image_url",
"role": "reference_image",
"image_url": {
"url": "asset://asset_123"
}
}
],
"resolution": "720p",
"duration": 5
}1. Create an asset group
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/v1/asset-groups" \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "seedance-demo-group",
"description": "reference assets for a Seedance run",
"provider": "byteplus_official"
}'Response:
{
"id": "group-1",
"name": "seedance-demo-group",
"description": "reference assets for a Seedance run",
"provider": "byteplus_official",
"requestId": "req-456"
}2. Upload the reference image into that group
curl -X POST "https://inference-api-pre-d80ca3.worldrouter.ai/v1/asset-groups/group-1/assets" \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "reference-image",
"description": "main character reference",
"type": "image",
"url": "https://example.com/reference.png"
}'You may also pass moderation_strategy as Default or Skip, and project_name if your BytePlus project requires it.
Response:
{
"id": "asset-1",
"asset_group_id": "group-1",
"name": "reference-image",
"description": "main character reference",
"type": "image",
"url": "asset://asset-1",
"source_url": "https://example.com/reference.png",
"provider": "byteplus_official",
"requestId": "req-789"
}3. Use asset://... in the generation payload
For uploaded assets, use the matching Seedance asset model. This example
uses Seedance 2.0; use seedance-2.5-asset for Seedance 2.5 assets:
{
"model": "seedance-2.0-asset",
"asset_group_id": "group-1",
"content": [
{
"type": "text",
"text": "The reference object moves through a cinematic studio scene."
},
{
"type": "image_url",
"role": "reference_image",
"image_url": {
"url": "asset://asset-1"
}
}
],
"resolution": "720p",
"duration": 5
}After submitting the request, follow Check task status to monitor the task and download the result.
Notes and limits
- Seedance requires a team-scoped key with enough available credits. Low balance returns
402 seedance_balance_too_low. - Pending Seedance jobs per user are capped. Too many running tasks return
429 seedance_too_many_pending_tasks. - Task reads are owner-scoped. You can only poll tasks created by the same authorized owner context.
- Asset groups and uploaded assets are also owner-scoped.
- New Seedance task and asset creation uses BytePlus. Existing historical Relay task IDs remain pollable through the status route and settle at their recorded rates.
- The public task status endpoint returns metadata and
content.video_url; there is no separate public/v1/videos/{id}/contentdownload route for Seedance.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
400 unsupported_model | The model ID is unsupported for this endpoint | Use one of the public Seedance model IDs from the table above on POST /api/v3/contents/generations/tasks. |
400 with “may contain real person” | The provider’s content filter read a reference image as a photo of a real person | Use an illustrated or AI-generated character reference. Real-person likenesses require provider authorization that is not enabled on this account. The error.guidance field repeats this. |
403 AccessDenied from BytePlus asset helpers | The BytePlus AK/SK lacks asset-library permissions | Grant the key actions such as ark:CreateAssetGroup, ark:CreateAsset, and ark:GetAsset. |
402 seedance_balance_too_low | The scoped team does not have enough available credits | Recharge on Credits and retry. |
403 media_resource_access_denied | The task, asset group, or asset belongs to another owner context | Reuse the same account/team/API key that created the resource. |
429 seedance_too_many_pending_tasks | Too many of your Seedance tasks are still running | Wait for active tasks to finish before creating more. |
424 with an error body | The upstream video provider failed or timed out | Transient provider failure — retry after a short wait. The body keeps the upstream error and upstream_status. |
See also
- Quickstart: API key and base URL setup.
- Models: current model catalog and pricing.
- API reference: chat-completions docs for text models.