Seedance 2.5 EvoLink API Guide: Live Integration Checklist
The official Seedance 2.5 API and EvoLink integration are live. You can now define a provider adapter, generate transport types, validate your domain payload, submit asynchronous jobs, test representative failures, and keep a Seedance 2.0 rollback.
Route availability alone does not make a workload production-ready. The correct goal is a live integration with measured quality, queue time, billing, and failure behavior for your own inputs.
Verification snapshot for August 7, 2026: the official developer API and EvoLink route are live. EvoLink exposes three workflow IDs, 4–30 seconds, 480p/720p, and the R2V reference split. Read the current price and account limits in EvoLink before scaled traffic. Seedance25API publishes a site-authored live integration aid and is not affiliated with ByteDance.
What belongs in this guide—and what belongs in the API reference
The API quickstart owns exact fields, endpoint examples, and the current request schema. This guide owns the engineering process around that schema.
| Question | Owning page |
|---|---|
| Which live pattern can be used today? | API quickstart and the current EvoLink documentation |
| Which request and polling shape can agents load? | The integration schema |
| How do we generate a typed client? | This guide |
| How do we test before scaling traffic? | This guide |
| How do we handle schema changes? | This guide |
| What can fall back to 2.0? | This guide and the 2.5 vs 2.0 decision guide |
| What is the final live price? | Pricing page and provider console |
Keeping those responsibilities separate prevents a Blog from becoming a stale copy of the documentation.

Define the production-validation boundary first
Write these statements into the project README or architecture decision record:
Before traffic: request validation, type generation, job lifecycle,
error mapping, fallback policy, logging, and callback idempotency.
Measure on the live route: output quality, latency, reference ingestion,
callback delivery, actual cost, failure behavior, and account rate limits.
This boundary changes the acceptance criteria. CI should pass without making a paid call; a small canary then validates live-only behavior before traffic expands.
Step 1: snapshot and version the integration schema
Do not generate client code from a moving remote URL on every production build. Download or vendor a reviewed snapshot, record its hash, and update it intentionally.
curl -fsSL https://seedance25api.io/openapi.json \
-o contracts/seedance-2.5.openapi.json
shasum -a 256 contracts/seedance-2.5.openapi.json
The integration schema models:
- live
POST /v1/videos/generationstask creation; - polling through
GET /v1/tasks/{task_id}; - a required workflow-specific
modelplusprompt; - the documented launch fields and reference limits;
- the current EvoLink task-state vocabulary:
pending,processing,completed, andfailed; - representative errors for local resilience testing.
EvoLink provider documentation remains authoritative. Pinning this independent schema gives the team reviewable contract changes while the live route and task retrieval stay behind a provider adapter.
Step 2: generate types but keep domain types independent
Generate transport types from the snapshot:
npx openapi-typescript@7 contracts/seedance-2.5.openapi.json \
-o src/generated/seedance-transport.ts
Do not let generated types become the application’s domain model. Generated transport code will change when the contract changes. Product concepts such as a review state, reference role, or accepted output belong in stable application types.
export type VideoRequest = {
prompt: string;
durationSeconds: number;
quality?: string;
references: Array<{
type: "image" | "video" | "audio";
url: string;
role: string;
}>;
};
export type VideoJob = {
id: string;
state: "queued" | "running" | "generated" | "failed";
outputUrl?: string;
errorCode?: string;
};
The adapter maps stable domain types to the current provider transport.
Step 3: keep route capabilities in configuration
Use the three live EvoLink workflow IDs, but keep the selected ID configurable instead of spreading it through UI components, database records, tests, and worker code.
type RouteConfig = {
baseUrl: string;
model: string;
maxDuration?: number;
qualities?: string[];
maxImages?: number;
maxVideos?: number;
maxAudio?: number;
enabled: boolean;
};
export const seedance25: RouteConfig = {
baseUrl: process.env.EVOLINK_BASE_URL ?? "https://api.evolink.ai/v1",
model: process.env.SEEDANCE_25_MODEL ?? "seedance-2.5-text-to-video",
maxDuration: Number(process.env.SEEDANCE_25_MAX_DURATION ?? 30),
qualities: (process.env.SEEDANCE_25_QUALITIES ?? "480p,720p").split(","),
maxImages: 30,
maxVideos: 10,
maxAudio: 10,
enabled: Boolean(process.env.EVOLINK_API_KEY),
};
The route becomes executable only when the human supplies EVOLINK_API_KEY. Add a startup assertion if code can submit without credentials, validate workflow-specific fields, and rerun smoke tests before expanding traffic.
Step 4: validate before the provider sees the request
Client-side controls improve usability, but server-side validation protects cost and reliability.
export function validateRequest(input: VideoRequest, route: RouteConfig) {
const errors: string[] = [];
if (!input.prompt.trim()) errors.push("prompt is required");
if (route.maxDuration && input.durationSeconds > route.maxDuration) {
errors.push(`duration must be at most ${route.maxDuration}`);
}
if (input.quality && route.qualities && !route.qualities.includes(input.quality)) {
errors.push(`quality ${input.quality} is not enabled for this route`);
}
const count = (type: VideoRequest["references"][number]["type"]) =>
input.references.filter((r) => r.type === type).length;
if (route.maxImages && count("image") > route.maxImages) errors.push("too many image references");
if (route.maxVideos && count("video") > route.maxVideos) errors.push("too many video references");
if (route.maxAudio && count("audio") > route.maxAudio) errors.push("too many audio references");
return errors;
}
URL reachability, media metadata, authorization, and signed-URL lifetime need their own checks. A valid URL string can still expire before the provider retrieves it.
Step 5: mock the full asynchronous lifecycle
A useful mock is stateful. It should return a job ID and advance through states rather than returning a completed video immediately.
{
"create": { "id": "mock-job-001", "status": "pending" },
"poll_sequence": [
{ "id": "mock-job-001", "status": "pending", "progress": 0 },
{ "id": "mock-job-001", "status": "processing", "progress": 40 },
{
"id": "mock-job-001",
"status": "completed",
"progress": 100,
"results": ["https://example.invalid/mock-output.mp4"]
}
]
}
The URL uses the reserved .invalid domain so no test can accidentally download an unrelated file.
Build fixtures for every meaningful outcome:
| Fixture | Expected application behavior |
|---|---|
200 create | Persist provider job ID before polling |
400 invalid request | Show field-level correction; never retry unchanged |
401 invalid key | Stop and ask the human to repair key configuration |
429 rate limited | Apply bounded backoff with jitter |
simulated 503 unavailable | Open route circuit and evaluate fallback eligibility |
completed | Save output, usage, and raw response; enter human review |
failed | Save reason; do not mark as transport success |
| duplicate callback | Return success without applying the state transition twice |
Also simulate a job that stays processing beyond the application deadline. The provider job may continue, but the user-facing operation needs a clear timeout state and a way to resume checking.
Step 6: schema-test the adapter, then contract-test the live route
The first schema test should prove that the application request is accepted by the pinned integration schema. The second should prove that every task state maps correctly. The third should fail when the schema changes unexpectedly. EvoLink provider documentation remains authoritative for contract differences.
import assert from "node:assert/strict";
const mapped = mapProviderJob({
id: "mock-job-001",
status: "processing",
progress: 40,
});
assert.deepEqual(mapped, {
id: "mock-job-001",
state: "running",
outputUrl: undefined,
errorCode: undefined,
});
Add a CI step that compares the reviewed contract snapshot with a newly fetched copy, but do not overwrite automatically:
curl -fsSL https://seedance25api.io/openapi.json \
-o /tmp/seedance-2.5.latest.json
diff -u contracts/seedance-2.5.openapi.json \
/tmp/seedance-2.5.latest.json
A diff is a review trigger, not proof of a breaking change. Description updates may be harmless; a required field, enum, state, or response change may require code and fixture updates.
Step 7: design retries by failure class
“Retry three times” is not a policy. Each failure class needs a different response.
| Failure | Retry? | Policy |
|---|---|---|
| Network timeout before response | Maybe | Retry with idempotency protection or reconcile before resubmitting |
400 | No | Correct the request |
401 | No | Repair secret or permission |
429 | Yes | Honor provider guidance; exponential backoff plus jitter |
simulated 503 | Limited | Open circuit; retry later or use an eligible fallback |
Job failed | Conditional | Retry only if reason is understood and policy allows |
| Poll timeout | Yes | Resume polling the same job; do not create a duplicate |
If the provider does not expose an idempotency key, the application needs its own submission record. A network timeout after the provider accepted a request is dangerous: blind resubmission may create two billable jobs.
Step 8: make fallback eligibility explicit
Seedance 2.0 can exercise the surrounding application today, but fallback is not a string replacement. A 2.5-planned request may exceed 2.0 duration or reference constraints.
function canFallbackToSeedance20(input: VideoRequest) {
return (
input.durationSeconds <= 15 &&
input.references.filter((r) => r.type === "image").length <= 9 &&
input.references.filter((r) => r.type === "video").length <= 3 &&
input.references.filter((r) => r.type === "audio").length <= 3
);
}
The limits above reflect the cited public EvoLink 2.0 guide and must still be checked against the active route. If the request is not eligible, give the user a choice: shorten, remove references, retry the 2.5 route later, or choose another verified route. Silent truncation is not a safe fallback.
Step 9: log the evidence needed before scaling traffic
Prepare structured fields now:
internal_request_id
provider_route
model_id
contract_version
provider_job_id
submit_attempt
http_status
provider_state
duration_requested
reference_counts
created_at / completed_at
usage_or_cost
output_url_expiry
review_outcome
fallback_route
Never log the bearer token or sensitive signed URLs without redaction. Logs should answer whether an error came from validation, authentication, capacity, generation, output retrieval, or human rejection.
Pre-production-traffic verification checklist
Contract-tested software still needs live evidence. Run these checks in order:
- Confirm the final model ID and account entitlement in provider documentation.
- Replace the planning assumptions with the live provider schema and review every difference.
- Create a short, low-risk smoke job.
- Verify every returned state and output access.
- Confirm the billing record for success and investigate failure billing separately.
- Test rate-limit and temporary-unavailability handling without creating a retry storm.
- Verify callback authentication, duplication, and ordering if callbacks are enabled.
- Run the frozen workload evaluation set.
- Enable only a small canary of eligible jobs.
- Confirm the kill switch returns traffic to a verified route.
The integration is ready for a canary only when the application behavior and provider behavior match. It is ready for broader production only when output acceptance, cost, latency, and error thresholds pass.
Recommended next step
Pin the machine-readable integration schema, generate types, and test the asynchronous state machine. Use the live 2.5 example in the API quickstart, the agent guide for safe key handoff, and Seedance 2.0 only where rollback eligibility is explicit.
That work is valuable even if a final Seedance 2.5 field changes. The adapter isolates change; the job, review, logging, and evaluation systems survive it.
Sources
- Seedance25API independent live integration schema
- Seedance25API API quickstart
- Seedance25API agent handoff guide
- EvoLink Seedance 2.5 access status
- EvoLink Seedance 2.0 reference-to-video documentation
- EvoLink task-detail documentation
- EvoLinkAI Seedance 2.0 public guide
Verification note: checked against EvoLink’s Seedance 2.5, Seedance 2.0, and task-detail documentation on August 7, 2026. The local OpenAPI file is a site-authored integration aid; EvoLink’s own documentation and console remain authoritative for current model IDs, request fields, limits, pricing, and error contracts.