Skip to content

Create a Video Task

Video generation on RouteAPI is an asynchronous task API. You submit a request, get back a task_id, poll that task until it reaches a terminal state, and then download the video. Every video model on the platform — Seedance, Sora, Veo, Wan, Kling, Hailuo, Vidu and others — is called through the same endpoints, because RouteAPI converts your request into the form the selected upstream expects.

Video models appear in GET /v1/models; their supported_endpoint_types shows openai-video for channels served through the OpenAI video format, and the console model page can set it per model. Either way, take the model ID from that list — see Models. Model-specific parameters are documented per vendor: Seedance, Hailuo, Wan. The OpenAI/Sora dialect of the same API is described in OpenAI video format.

MethodPathPurposeDocumented in
POST/v1/video/generationsSubmit a generation taskThis page
GET/v1/video/generations/{task_id}Read the task recordGet a video task
POST/v1/videosSubmit a generation task (OpenAI dialect)OpenAI video format
GET/v1/videos/{task_id}Read the task as an OpenAI video objectOpenAI video format
POST/v1/videos/{video_id}/remixCreate a task derived from an existing videoOpenAI video format
GET/v1/videos/{task_id}/contentDownload the finished video bytesGet a video task

POST /v1/video/generations and POST /v1/videos are two paths to the same task operation with different request and response dialects. The submit response is an OpenAI video object on both; the GET endpoints differ (task record vs. video object), so pair each submit path with its matching GET.

  1. Submit — send the prompt and model to POST /v1/video/generations (or POST /v1/videos) and store the returned task_id. The estimated cost is reserved from your balance at this point.
  2. Poll — call the matching GET endpoint every 10–15 seconds. Generation commonly takes one to several minutes; higher resolution and longer duration take longer.
  3. Finish — when the status reports success, download the video or read its URL. If the task fails or never reaches a terminal state, the reserved amount is returned.
POST /v1/video/generations

Every video model accepts this common envelope. Model-specific options go in metadata; the vendor pages list the keys each adaptor reads.

FieldTypeRequiredDescription
modelstringYesModel ID from GET /v1/models
promptstringYesText prompt. A missing, empty, or whitespace-only prompt is rejected with 400
imagestringNoSingle image (URL or Base64/data URI). Treated as the first entry of images
imagesstring[]NoReference / first-frame images. Meaning depends on the model
sizestringNoSize or resolution hint such as 1280x720 or 720p, depending on the model
durationintegerNoDuration in seconds. RouteAPI rejects negative values and values above 3600
secondsstringNoLegacy string form of the duration. Models that read it use it in place of duration
input_referencestringNoOpenAI-style reference image field, read by the adaptors that support one (for example Sora and Wan)
ratiostringNoAspect ratio such as 16:9 or 9:16; read by the Seedance adaptor
resolutionstringNoOutput resolution tier such as 720p or 1080p; read by the Seedance adaptor
generate_audiobooleanNoGenerate a soundtrack. On Seedance an explicit false is forwarded rather than dropped
metadataobjectNoProvider-specific parameters. For Seedance, values in metadata win over the top-level equivalents

Field names RouteAPI does not recognize in the top-level body are ignored; put model-specific parameters under metadata.

multipart/form-data bodies are also accepted on the submit endpoints: scalar form fields map to the same names, and files upload directly (for example input_reference for Sora). Unknown form fields become metadata entries.

Terminal window
curl https://api.routeapi.ai/v1/video/generations \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0-fast",
"prompt": "An orange cat stretching on a windowsill at sunrise",
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
"generate_audio": false
}'
{
"id": "task_G2RdWGt4t1nck5fYqTjwREKJo8Ze4RAV",
"task_id": "task_G2RdWGt4t1nck5fYqTjwREKJo8Ze4RAV",
"object": "video",
"model": "seedance-2.0-fast",
"status": "queued",
"progress": 0,
"created_at": 1792048458
}

task_id (and its alias id) is the RouteAPI task ID; every later call uses it. The upstream provider’s task ID is not the value you poll with — where it is visible at all, it sits inside the stored upstream payload (data.data on the task record).

A successful submit also returns an X-New-Api-Other-Ratios response header containing the billing multipliers that were applied — for example {"seconds":5,"size":1} for Sora, or {"video_input":0.608695652174} for a Seedance request with video input. It is useful when reconciling the charge.

Once routed, the task endpoints answer with the task error shape:

{ "code": "invalid_request", "message": "prompt is required", "data": null }
StatusCodeMeaning
400invalid_requestMissing or blank prompt, a metadata field with the wrong type, or a body that cannot be parsed
400invalid_jsonMalformed JSON on the adaptors that validate the body directly (Sora and Wan)
400missing_modelmodel is absent; returned by the adaptors that validate the body directly (Sora and Wan). Other paths reject a missing model before routing, as a middleware error
400invalid_secondsduration / seconds is negative or above 3600
400invalid_sizeThe model does not accept this size, for example an unsupported Sora size
400model_price_errorRouteAPI could not price the model; nothing is submitted
400model_not_supportedThe model resolves to one the channel no longer serves, such as Seedance 1.x
400task_not_existA remix whose origin task is unknown or belongs to another account
400task_source_unavailableA remix whose origin task’s channel was deleted or disabled, or whose adaptor is missing
403insufficient_user_quota / pre_consume_token_quota_failedThe account balance or the Key quota cannot cover the estimated cost; nothing is submitted
429—Upstream capacity exhausted; the message is replaced with a generic “try again later” text
500build_request_failed, do_request_failed, invalid_responseThe task could not be converted, the upstream connection failed, or the upstream returned no task ID
500get_channel_failed, task_persistence_failed, gen_relay_info_failedRouteAPI could not route or record the task; nothing is charged (any reservation is refunded)
502upstream_task_id_missingThe upstream accepted the task but returned no task ID; the task is failed so the reservation is released
anyfail_to_fetch_taskThe upstream answered the submit with a non-200 status; the HTTP status is the upstream’s

Requests rejected before routing — a missing or invalid API Key (401), an IP restriction, a group without access, a model outside the Key’s allowlist (403), or a model with no available channel (503, code model_not_found) — use the standard middleware error body {"error": {"message": ..., "type": "error", "code": ...}}, not the task shape.

Failures that happen after submission (content review, provider timeout, cancellation) do not surface as HTTP errors. They appear as FAILURE in the task record together with fail_reason, and the reserved amount is refunded.

  • Get a video task — poll the record, read the status, and download the result.
  • Seedance, Hailuo, Wan — model-specific parameters and limits.
  • Assets — upload reusable image, video, and audio material and reference it with asset://.
  • Common Errors — status codes shared by all model endpoints.