Skip to main content

Seedance 2 API Docs: API Keys, Model IDs, Calls, and Callbacks

A
9 min readAI Video Generation

Pick one Seedance 2 API route, keep its key, host, model ID, and task contract together, then submit once and reconcile callbacks with polling.

Seedance 2 API Docs: API Keys, Model IDs, Calls, and Callbacks

The Seedance 2 API is an asynchronous task API: POST creates a job and returns an ID; GET retrieves that job; a callback can report state changes; the finished video is downloaded only after succeeded. The integration fails when a correct API key, host, or model ID is copied from a different route.

Choose one complete route tuple before writing code. These contracts were checked on July 18, 2026:

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 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.0#Seedance API#API Documentation#BytePlus ModelArk#Volcengine Ark#Async API
Share: