Skip to main content
Draft mode lets you preview a Seedance 2.5 video at 480p, then finalize the exact same shot at 1080p with one more request. The final reuses the draft’s prompt, media, and settings, so what you approved is what you get. It is a good way to save money while you are iterating on your motion, dialogue, and shot details before committing to a 1080p generation. The flow has two calls:
  1. Draft. Send your normal request with draft: true. You get a 480p video and a draft_task_id.
  2. Final. Send the draft_task_id back with the same model. You get the 1080p video. No prompt needed.
Supported model: bytedance-seedance-2-5-text-to-video Base URL: https://hub.oxen.ai/api. Authenticate every request with Authorization: Bearer $OXEN_API_KEY. Draft mode works on both the queue (POST /ai/queue) and the sync endpoint (POST /ai/videos/generate). It is also available in the Oxen.ai UI: render a draft, then click to render the final.
We recommend the async queue workflow. Seedance generations may take a long time, and your HTTP connection may time out in sync mode.

Seedance 2.5 - Text to Video API reference

Full parameter table, request builder, and sample code for the underlying model.
We recommend the async queue for draft mode. Seedance generations can take several minutes, and in sync mode your HTTP connection may time out before the video is ready. Enqueue returns a generation_id right away; poll (or listen for the completion event) until the generation finishes.

1. Enqueue a draft

Add draft: true to a normal request. Any resolution you send is overridden to 480p.
Response:

2. Poll the draft

status moves from queued to processing and videos stays empty until the generation has a result. Once status is succeeded, read the draft ID from videos[0]:
If you consume the media_generation_completed event instead of polling, it carries the same videos list beside its url.

3. Enqueue the final

Response:

4. Poll the final

Poll GET /ai/queue/{generation_id} as before. The succeeded final lists its video with only a url. Its top-level draft_task_id names the draft it came from, so you can link the two in your own records.

Sync flow

The sync endpoint holds the connection open and returns the finished video. It is fine for quick experiments, but for anything else prefer the async queue above, since a long Seedance render can outlast your HTTP connection.

1. Render a draft

Add draft: true to a normal request. Any resolution you send is overridden to 480p.
The response lists the video with its draft ID and expiry:
Store videos[0].draft_task_id and videos[0].draft_expires_at with the draft. You need the ID to render the final.

2. Render the final

Send the draft_task_id back exactly as you received it, with the same model. Leave out prompt, duration, and other settings.
The final is 1080p at the draft’s duration and audio setting. Its item carries only a url:

Reference

Request parameters

Both endpoints accept these fields in the JSON body. Settings like aspect ratio, audio, and seed are set on the draft and locked for the final. The final ignores them if resent, along with any prompt. The queue generation record still echoes whatever you sent, so do not read the final’s settings back from it. Read them from the draft.

Response fields

Every endpoint lists media the same way: a videos array of items with a stored url, plus any fields you can act on.

Endpoints

Rules, billing, and errors

Rules

  • Drafts expire after 7 days. Render the final before draft_expires_at. After that, render a new draft.
  • One draft, many finals. A draft ID stays valid until it expires, so you can re-render the final if you need to.
  • The final is locked to the draft. To change the prompt, media, duration, aspect ratio, audio, or seed, render a new draft.
  • Use the same model. Send the final to the model that produced the draft.

Billing

Drafts and finals are each billed as a normal video at their resolution. A draft costs the same as any 480p render. A final costs the same as any 1080p render, using the duration and audio of the finished video. The cost estimate for a final shows a range from silent to with-audio, since the final inherits the draft’s audio setting. Pass the draft’s duration on the final request to tighten the estimate. It does not change the render. Every render, sync or queued, appears on your requests page and in your usage totals.

Errors

The sync endpoint returns an HTTP 400 with the error in the body. The queue accepts the request and reports the same error on the generation once it runs: status is failed, videos is empty, and error_message explains why. Sync error body for an unknown draft ID:

Integration guide

This section is written so a coding agent can implement draft mode from it directly. Point Claude Code or a similar tool at this page and ask it to add draft mode to your Seedance 2.5 integration.

Checklist

  • Add a draft option to your Seedance 2.5 request builder that sets "draft": true.
  • Read draft_task_id and draft_expires_at from videos[0] on the sync response, the succeeded queue generation, or the media_generation_completed event.
  • Persist both fields next to the draft’s video URL and prompt.
  • Add a “render final” action that sends only model and draft_task_id.
  • Hide or disable that action once draft_expires_at has passed.
  • Lock prompt and settings in your UI for finals. Editing them means a new draft.
  • Link each final to its draft using the final generation’s top-level draft_task_id.
  • Read media from videos[]. Treat an empty videos list as not ready.

Reference implementation (Python)

A minimal client covering both paths. It uses only requests.

Prompt for your coding agent