Skip to main content

Seedance 2.5 API Guide: Model IDs, Python, and Node.js

•••9 min read•AI Video Generation

Seedance 2.5 is a confirmed product, but a first-party ModelArk 2.5 ID is not yet present in the public catalog. Integrate without guessing the ID.

Seedance 2.5 API route from release status and provider model ID to Python and Node.js asynchronous integration

As of August 4, 2026, ByteDance has published the Seedance 2.5 product page, but BytePlus's current public video API and model-pricing catalog still list the Seedance 2.0 series. The 2.5 product is real; a first-party ModelArk 2.5 model ID is not yet verifiable in the public catalog. The safe first step is to pin one provider-owned route instead of guessing an ID from a search result or wrapper.

Seedance 2.5 product status, official API catalog, and provider-scoped model ID decision

Separate the Seedance 2.5 release from API availability

The official Seedance 2.5 page describes clips up to 30 seconds, two extensions, stronger reference and editing behavior, white-model control, and green-screen editing. It does not publish an API host, credential flow, model ID, request schema, or account rollout.

The BytePlus create-task reference, updated July 31, 2026, still documents public capabilities as Seedance 2.0 series. Its current model and pricing table lists three 2.0 IDs and no 2.5 entry. A string such as dreamina-seedance-2-5-260628 may appear on third-party pages, but that does not make it a published BytePlus ID.

SurfaceWhat it establishesSafe integration decision
ByteDance Seed product pageProduct name and creative capabilitiesUse it for capability planning, not API parameters
BytePlus or Volcengine model catalogActivated IDs, key scope, host, and task contractEnable 2.5 only when the account or first-party catalog actually lists it
Third-party 2.5 APIA provider may expose its own alias and endpointKeep its host, key, ID, payload, billing, and policy together

If production must ship now, use a currently cataloged Seedance 2.0 fallback. If the workload specifically requires 2.5, wait for the first-party account catalog or choose a provider that documents the complete route and its limits.

Choose one complete route tuple before writing code. The following are current Seedance 2.0 fallback contracts, not proof of a first-party 2.5 rollout:

RouteBase URL and key scopeModel namespaceCreate, query, and download contract
BytePlus ModelArk directhttps://ark.ap-southeast.bytepluses.com/api/v3; a ModelArk API key created inside the correct resource projectdreamina-seedance-2-0-260128, dreamina-seedance-2-0-fast-260128, or dreamina-seedance-2-0-mini-260615POST /contents/generations/tasks; GET /contents/generations/tasks/{id}; read content.video_url from the succeeded task
Volcengine Ark China directhttps://ark.cn-beijing.volces.com/api/v3; a key for the China-region Ark accountdoubao-seedance-2-0-260128 or doubao-seedance-2-0-fast-260128; verify the account's current Mini ID instead of guessing itThe same create/query path shape; read the succeeded task's output
laozhang.ai gatewayhttps://api.laozhang.ai/seedance/api/v3; a token assigned to the SeeDance2 groupdoubao-seedance-2-0-260128 or doubao-seedance-2-0-fast-260128Ark-shaped create/query paths; compatibility download at https://api.laozhang.ai/v1/videos/{id}/content

Do not put a dreamina-* ID on the China or gateway host. Do not append BytePlus's host path to laozhang.ai. A route is the host, key scope, model namespace, and task contract together.

Choose the route before the API key

Use BytePlus ModelArk direct when the application needs first-party international account ownership, the current Standard/Fast/Mini catalog, or endpoint-level controls. Its Seedance 2 tutorial owns the three current dreamina-* IDs, while ModelArk key management explains resource-project keys and optional model, endpoint, and IP restrictions.

Use Volcengine Ark direct for China-region infrastructure and doubao-* contracts. The public reference can show an older example ID, so check the account's current model list before deployment. The Standard and Fast IDs above were checked against current first-party surfaces; the exact Mini suffix was not inferred.

Use the laozhang.ai Seedance relay when a single developer gateway and its documented relay are operationally simpler. Move to official direct access if the project needs a model variant, region, account control, or feature the relay does not expose. The current relay documentation does not support real-person face workflows; review the real-person input boundary before accepting those assets.

This is a route decision, not a price comparison. Availability still depends on the reader's account, region, activation, and balance.

Create and protect the API key

For BytePlus, create the key inside the ModelArk resource project that owns the intended model or endpoint. A key or activation from another project or region may not work against the AP host. Limit its scope where possible, keep it in a server-side environment variable, and never place it in browser JavaScript, a mobile binary, a public repository, or a callback URL.

bash
export ARK_API_KEY="replace-on-your-server" export SEEDANCE_BASE_URL="https://ark.ap-southeast.bytepluses.com/api/v3" export SEEDANCE_MODEL="dreamina-seedance-2-0-260128"

Treat those values as one configuration object. Reject a mismatch before it can create a paid task:

ts
function assertSeedanceRoute(baseUrl: string, model: string, key: string) { if (!key) throw new Error("Missing server-side Seedance API key"); const bytePlus = baseUrl.includes("bytepluses.com"); const china = baseUrl.includes("volces.com"); const relay = baseUrl.includes("api.laozhang.ai/seedance/api/v3"); if (bytePlus && !model.startsWith("dreamina-seedance-")) { throw new Error("BytePlus requires a dreamina-* model ID"); } if ((china || relay) && !model.startsWith("doubao-seedance-")) { throw new Error("This route requires a doubao-* model ID"); } if (!bytePlus && !china && !relay) throw new Error("Unknown Seedance route"); }

The guard prevents a known configuration error. It cannot prove account activation or model access.

Submit and poll one task in Python

This example targets an Ark-shaped asynchronous contract. Set all three environment variables from the same provider's current documentation or console. SEEDANCE_MODEL can be a cataloged 2.0 fallback or a provider-owned 2.5 ID that you have independently verified.

python
import os import time import requests base_url = os.environ["SEEDANCE_BASE_URL"].rstrip("/") api_key = os.environ["SEEDANCE_API_KEY"] model = os.environ["SEEDANCE_MODEL"] headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} payload = { "model": model, "content": [{"type": "text", "text": "A ceramic cup rotates slowly on a clean studio table"}], "ratio": "16:9", "resolution": "720p", "duration": 5, "generate_audio": True, } response = requests.post(f"{base_url}/contents/generations/tasks", headers=headers, json=payload, timeout=30) response.raise_for_status() task_id = response.json()["id"] # Persist before doing anything else. while True: response = requests.get(f"{base_url}/contents/generations/tasks/{task_id}", headers=headers, timeout=30) response.raise_for_status() task = response.json() if task["status"] in {"succeeded", "failed", "expired"}: print(task) break time.sleep(5)

If the create request times out before returning an ID, do not silently submit a second job. Mark the local job as having an unknown submission outcome and reconcile it through callbacks, request logs, or provider support.

Run the same contract with Node.js

Node.js 18 and later include fetch. Keep the API key in a server environment; this code is not for browser-side JavaScript.

js
const baseUrl = process.env.SEEDANCE_BASE_URL.replace(/\/$/, ""); const apiKey = process.env.SEEDANCE_API_KEY; const model = process.env.SEEDANCE_MODEL; async function request(path, init = {}) { const response = await fetch(`${baseUrl}${path}`, { ...init, headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", ...init.headers }, }); const contentType = response.headers.get("content-type") || ""; if (!contentType.includes("application/json")) throw new Error(`Expected JSON, received ${contentType}`); const data = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${JSON.stringify(data)}`); return data; } const created = await request("/contents/generations/tasks", { method: "POST", body: JSON.stringify({ model, content: [{ type: "text", text: "A ceramic cup rotates slowly on a clean studio table" }], ratio: "16:9", resolution: "720p", duration: 5, generate_audio: true }), }); const taskId = created.id; // Persist this before polling. for (;;) { const task = await request(`/contents/generations/tasks/${taskId}`); if (["succeeded", "failed", "expired"].includes(task.status)) { console.log(task); break; } await new Promise((resolve) => setTimeout(resolve, 5000)); }

Python and Node.js share one Seedance async create, task persistence, polling, and output-copy lifecycle

Submit the first Seedance 2 API call

This request is specifically for BytePlus Standard. It creates one async task and asks for a callback:

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 calm tabletop product shot, slow camera move, natural studio sound" }], "ratio": "16:9", "resolution": "720p", "duration": 5, "generate_audio": true, "callback_url": "https://api.example.com/webhooks/seedance", "priority": 0 }'

The response is a task ID, not a video. Create a local job and normalized request hash before or around submission, then persist the provider ID immediately. Bind that record to the route, model, user, prompt/media fingerprint, and output settings.

BytePlus currently documents priority as a Seedance 2-only integer from 0 through 9. A larger value moves queued work ahead of lower-priority work inside the same endpoint. It does not interrupt running tasks, cross endpoints, apply to offline flex inference, or guarantee faster generation.

The current BytePlus choices are:

  • dreamina-seedance-2-0-260128: quality-first;
  • dreamina-seedance-2-0-fast-260128: speed/cost balance;
  • dreamina-seedance-2-0-mini-260615: cost-performance.

These labels do not make the IDs portable to other routes. The BytePlus account also needs an active Seedance 2 resource package with available balance.

Query the task; do not create a replacement

Retrieve the task with the same base URL, key, and provider ID:

bash
curl \ "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/$TASK_ID" \ -H "Authorization: Bearer $ARK_API_KEY"
StateApplication meaningSafe next action
queuedAccepted and waitingWait for callback or poll later; never create a replacement
runningGeneration startedKeep the same provider ID
succeededOutput availableMark success and copy the output into durable storage
failedProvider ended the task with an errorRecord and classify the error before a new user-authorized task
expiredExecution window endedMark terminal and require an explicit new-generation decision

Treat content.video_url as a delivery URL, not the permanent product URL. Copy it promptly to controlled storage and make that copy retryable without re-running generation.

Make callbacks idempotent and polling reparative

callback_url is optional. ModelArk sends a payload shaped like the retrieve-task response when status changes. For failed delivery of succeeded or failed, the current documentation says it retries three times when no successful confirmation arrives within five seconds.

Repeated terminal delivery means callback processing must be idempotent. A deploy or handler failure also means polling must remain available. Callback and polling are two paths into one durable job state machine.

The public reference checked for this article does not establish a webhook-signature scheme that is safe to claim universally. Do not invent one. Require HTTPS, cap payload size, accept only the expected content type, find the task ID in the local database, verify its route and job ownership, reject illegal state regressions, and return only after committing the transition.

ts
const terminal = new Set(["succeeded", "failed", "expired"]); async function applyProviderState(event: SeedanceTask) { const job = await jobs.findByProviderTaskId(event.id); if (!job) throw new Error("Unknown provider task"); await jobs.transaction(async (tx) => { const current = await tx.forUpdate(job.id); if (current.providerStatus === event.status) return; if (terminal.has(current.providerStatus)) return; await tx.update(job.id, { providerStatus: event.status, providerPayload: event }); if (event.status === "succeeded") await tx.enqueueOutputCopy(job.id); }); }

A repair poller queries non-terminal jobs whose callback deadline passed and applies the same transition function.

Enforce the duplicate-create stop rule

The dangerous case is a create timeout after the provider accepted the request but before the client received the task ID.

Stop rule: if a local job may have reached the provider, do not issue a second POST because the HTTP client timed out. Reconcile the request hash, provider ID, request log, and any callback. If an ID exists, query it. If acceptance remains unknown, surface ā€œsubmission state unknownā€ for review instead of silently purchasing another generation.

OperationRetry policy
Create before any request left the processSafe to try once
Create timed out with acceptance unknownStop and reconcile the existing job
Query a stored task IDRetry transport failures with bounded backoff
Process callbackReplay through idempotent transitions
Copy succeeded outputRetry without creating a new video
Provider task failedClassify validation, policy, account, or transient failure first

Read route probes correctly

On July 18, 2026, the documented create paths were probed with POST {} and no credential. No task was created.

ProbeResponseCorrect interpretation
BytePlus AP createHTTP 401 JSONReached the auth boundary; does not prove activation or generation
Volcengine China createHTTP 401 JSONChina path is live and protected; account/model remain untested
Correct laozhang.ai /seedance/api/v3/...HTTP 401 JSONRelay expects auth; a default-group token is not proven
laozhang.ai path missing /seedanceHTTP 404 JSONWrong route
Obsolete laozhang.ai /seedance/v3/...HTTP 200 HTMLHTML is not an API success

Check status and content type. None of these was an authenticated generation test, and this article does not claim a video was generated.

After authentication, diagnose the contract layer before changing the prompt: model not found means recheck the route's model namespace and the account's current model list; an unsupported-field error means compare the payload with that route's current request schema instead of assuming fields are portable across providers; any HTML response still points back to the URL layer.

Reference media and production boundaries

ByteDance's Seedance 2 page identifies text, image, audio, and video inputs. The selected API route's current reference—not the model page—owns exact fields and limits. In the Ark contract, media goes in content. Keep first/last-frame generation separate from multimodal references, and do not submit audio alone; audio requires at least one image or video.

For real-person assets, consent and route policy belong before the call. After the route works, use the Seedance 2 prompt guide for creative control rather than debugging configuration with elaborate prompts. If the remaining question is provider selection, use the separate Seedance 2 API provider comparison.

Before launch, version the route tuple, keep the key server-side, persist the task ID, make callbacks idempotent, retain polling repair, stop duplicate creates, reject HTML health-check responses, and recheck current endpoints and model IDs.

#Seedance 2.5#Seedance API#Model ID#Python#Node.js#BytePlus ModelArk
Share: