Skip to main content

How to Call the Seedance 2.0 API: Submit, Poll, Download, References, and Retries

A
8 min readAI Video Generation

Call Seedance 2.0 as an async video job: submit once, store the task ID, poll or receive a callback, copy the returned video URL, and make retries idempotent.

How to Call the Seedance 2.0 API: Submit, Poll, Download, References, and Retries

Seedance 2.0 is called as an asynchronous video-generation task. A production integration should create one task, persist the returned ID, poll or receive a callback until a terminal state, copy the returned video_url into durable storage, and make retries operate on your own job record instead of blindly submitting duplicates.

For the BytePlus ModelArk route, keep the base URL, model ID, request body, and billing route together. The current global task endpoint is https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks, and the route-owned Seedance 2.0 model IDs are dreamina-seedance-2-0-260128 and dreamina-seedance-2-0-fast-260128. For the China-region Volcengine Ark route, use the China endpoint and the doubao-* model IDs instead of mixing the two routes.

Seedance 2.0 API async lifecycle from submit to polling and download

Submit one async task

Treat the create call as the only place where generation is started. Your application should validate the prompt, model route, references, aspect ratio, duration, and callback URL before it sends the request. After submission, store the returned task ID with your own job ID, request hash, model ID, user ID, and requested output settings.

bash
curl -X POST "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks" \ -H "Authorization: Bearer $ARK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "dreamina-seedance-2-0-260128", "content": [ { "type": "text", "text": "A quiet product demo shot, slow camera move, clean studio light" } ], "ratio": "16:9", "resolution": "720p", "duration": 5, "generate_audio": false, "return_last_frame": true, "callback_url": "https://example.com/webhooks/seedance" }'

The create response gives you the task ID, not the final video. That distinction matters for retries: if the network drops after submission, first check whether your own job already has a provider task ID before creating another generation.

Use direct request-body parameters for resolution, ratio, duration, seed, watermark, and related controls. The current docs still describe older prompt-suffix parameters, but direct body fields are the safer production contract because invalid values fail visibly instead of being silently ignored.

Poll or handle callbacks

Seedance task states are not a progress bar; they are a queue lifecycle. Store them as a finite state machine:

Provider statusApp meaningNext move
queuedAccepted but not runningPoll with backoff or wait for callback
runningGeneration is in progressKeep waiting; do not resubmit
succeededOutput is readyDownload and copy content.video_url
failedProvider rejected or failed the taskSave error.code and error.message; decide whether retry is allowed
expiredThe task exceeded its execution windowMark retryable only if the request is still useful
cancelledA queued task was cancelledStop polling and surface cancellation
bash
curl -X GET \ "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/$TASK_ID" \ -H "Authorization: Bearer $ARK_API_KEY"

Polling can start with a short delay, then back off to a steady interval such as 10-20 seconds. Keep a maximum wall-clock timeout in your own system even if the provider has its own execution_expires_after value. If you use callbacks, still keep a poller as repair logic for missed webhook delivery, deploy outages, or signature verification bugs.

Callback handlers should be idempotent. Accept the provider payload, validate that the task ID belongs to an existing job, update the status only if the new state is allowed from the previous state, and enqueue the download step when the task becomes succeeded.

Download and store the result

On success, the retrieve response returns content.video_url as an MP4 URL. Do not leave the user-facing product dependent on that temporary URL. The official response contract says generated video URLs are cleaned after 24 hours, so your success handler should copy the file into your own object storage immediately.

ts
async function persistSeedanceOutput(job: Job, providerPayload: SeedanceTask) { const videoUrl = providerPayload.content?.video_url; if (!videoUrl) throw new Error("Seedance succeeded without video_url"); const response = await fetch(videoUrl); if (!response.ok) { throw new Error(`download failed: ${response.status}`); } await storage.putObject({ key: `seedance/${job.id}/output.mp4`, body: response.body, contentType: "video/mp4", }); if (providerPayload.content?.last_frame_url) { await copyUrlToStorage(providerPayload.content.last_frame_url, `seedance/${job.id}/last-frame.png`); } }

Save the provider task payload beside the copied asset. You will need it for support, billing reconciliation, and reproduction: model ID, task status, seed, ratio, resolution, duration or frames, generate_audio, and usage.total_tokens.

Seedance 2.0 API reference media map for images, video, audio, first frames, and last frames

Pass reference media in content

Seedance 2.0 supports text-only generation, first-frame image-to-video, first-and-last-frame image-to-video, multimodal references, and reference video or audio inputs. These are not just optional attachments; the content array describes the generation mode.

For first-frame generation, pass one image item and set role to first_frame or omit the role if the route allows that mode. For first-and-last-frame generation, pass two image items and set role to first_frame and last_frame. For multimodal reference generation, use reference_image, reference_video, and reference_audio roles, and keep the mode separate from strict first/last-frame jobs.

json
{ "model": "dreamina-seedance-2-0-260128", "content": [ { "type": "text", "text": "Use [image 1] as the product design reference and keep the shot minimal." }, { "type": "image_url", "image_url": { "url": "https://cdn.example.com/reference-product.webp" }, "role": "reference_image" } ], "ratio": "16:9", "duration": 5, "generate_audio": false }

Reference rules worth enforcing before submission:

  • Use public URLs, Base64 data URLs, or supported asset IDs for images; avoid Base64 for large files because request size limits still apply.
  • Keep image dimensions and aspect ratios inside the provider limits before you call the API.
  • Use video references only with Seedance 2.0 routes that support video input; keep individual and total reference duration inside the documented limits.
  • Do not submit audio by itself. The current contract requires audio to accompany at least one image or video reference.
  • Keep face and authorization boundaries explicit. If your workflow includes real people, build a review and consent layer before submission.

Make retries idempotent

The most expensive Seedance bug is duplicate generation. A retry policy should be based on your own durable job record, not on whether the HTTP client wants to replay a request.

Create a deterministic request hash from the normalized model ID, route, prompt, media URLs or asset IDs, output settings, and end-user identifier. When a create request begins, insert a job row with that hash and a local status such as submitting. If a second request arrives with the same hash, return the existing job instead of submitting a new provider task.

Retry only the operations that are safe to repeat:

OperationRetry rule
Create task before a provider ID is storedRetry after checking the job row and request hash
Create task after a provider ID is storedDo not resubmit; resume polling that ID
Poll taskRetry with backoff on network and 5xx failures
Callback processingSafe to replay if state transitions are idempotent
Download outputSafe to retry until the temporary URL expires
Failed generationRetry only after classifying the provider error

For failed tasks, separate bad input from transient infrastructure. Validation errors, unsupported media, policy failures, and incompatible parameters should return a repair message to the user. Rate limits, timeouts, and temporary 5xx responses can go through backoff with a cap. A useful production rule is three bounded attempts for transient transport work and zero automatic resubmissions for provider-level generation failures unless the error code is known to be retryable.

Seedance 2.0 API retry decision matrix for create timeouts, queued tasks, succeeded outputs, and failed jobs

A production checklist

Before exposing the integration to users, confirm that each layer is owned:

  • Configuration keeps BytePlus dreamina-* IDs separate from Volcengine doubao-* IDs.
  • The create endpoint, retrieve endpoint, model ID, and billing route are stored together.
  • The app stores provider task IDs before polling starts.
  • Webhooks are idempotent and can be replayed.
  • Polling has backoff, a maximum wall-clock timeout, and a repair path for missed callbacks.
  • Successful video_url outputs are copied to durable storage before the 24-hour cleanup window matters.
  • Reference media is validated before submission.
  • Retry behavior cannot create duplicate paid generations for the same app-level job.

FAQ

Is the Seedance 2.0 API synchronous?

No. Treat it as an async task API. The create call returns a task ID; the generated MP4 appears later in the retrieve response after the task reaches succeeded.

Should I use polling or callbacks?

Use callbacks for low-latency updates and keep polling as repair logic. A callback-only system can lose state during deploys, verification bugs, or temporary endpoint failures.

How long can I keep the returned video URL?

Copy it immediately. The returned content.video_url is a temporary MP4 URL and the official response contract says generated videos are cleaned after 24 hours.

Can I pass both first/last frames and reference media in one task?

Keep those modes separate. First/last-frame generation uses first_frame and last_frame; multimodal reference generation uses reference_image, reference_video, and reference_audio. If you need exact first and last frames, use the first/last-frame mode rather than trying to imply it through references.

What should happen when a create request times out?

Do not immediately submit a second task. Look up your local job by request hash. If a provider task ID was stored, resume polling it. If no provider ID exists and the create attempt definitely did not complete, retry the create operation with the same local job record.

Share:

laozhang.ai

One API, All AI Models

AI Image

Gemini 3 Pro Image

$0.05/img
80% OFF
AI Video

Sora 2 · Veo 3.1

$0.15/video
Async API
AI Chat

GPT · Claude · Gemini

200+ models
Official Price
Served 100K+ developers
|@laozhang_cn|Get $0.1