Skip to content

Get a Video Task

After submitting a task through Create a video task, poll GET /v1/video/generations/{task_id} until the task reaches a terminal state, then download the video from GET /v1/videos/{task_id}/content. Polling reads a task record that RouteAPI refreshes in the background, so a 10–15 second interval is enough.

GET /v1/video/generations/{task_id}

Tasks are scoped to the API Key’s user: a task_id that belongs to another account is reported as task_not_exist.

Terminal window
curl https://api.routeapi.ai/v1/video/generations/task_G2RdWGt4t1nck5fYqTjwREKJo8Ze4RAV \
-H "Authorization: Bearer $ROUTEAPI_KEY"
{
"code": "success",
"message": "",
"data": {
"id": 4512,
"created_at": 1792048450,
"updated_at": 1792048569,
"task_id": "task_G2RdWGt4t1nck5fYqTjwREKJo8Ze4RAV",
"platform": "54",
"user_id": 1024,
"group": "default",
"channel_id": 18,
"quota": 123456,
"action": "generate",
"status": "SUCCESS",
"progress": "100%",
"fail_reason": "",
"result_url": "https://...mp4",
"submit_time": 1792048458,
"start_time": 1792048461,
"finish_time": 1792048569,
"properties": {
"input": "",
"origin_model_name": "seedance-2.0-fast"
},
"data": { "id": "cgt-xxxxxxxx", "status": "succeeded" }
}
}
FieldDescription
code"success" on a readable task; failures use the task error shape described below
data.idInternal row ID; not used in any request
data.task_idRouteAPI task ID — the value you poll and download with
data.statusNOT_START, SUBMITTED, QUEUED, IN_PROGRESS, SUCCESS, or FAILURE
data.progressProgress string such as "30%" or "100%"
data.result_urlVideo URL once the task succeeded. It may point at the RouteAPI download endpoint or directly at an upstream URL with a limited lifetime
data.fail_reasonFailure reason; empty otherwise
data.submit_time / start_time / finish_timeUnix seconds. start_time and finish_time are 0 until the task starts and finishes
data.created_at / updated_atUnix seconds, the row’s creation and last-update time
data.quotaQuota charged for the task
data.platformNumeric upstream channel type of the channel that ran the task
data.group / data.channel_id / data.user_idBilling group, channel, and owning account. Useful when asking support about a task
data.actionWhat the task does: generate, textGenerate, firstTailGenerate, referenceGenerate, or remixGenerate
data.propertiesStored task properties: origin_model_name, upstream_model_name, and the upstream request snapshot in input when the adaptor records one. Intended for debugging
data.dataThe upstream provider’s latest task payload, stored for debugging. Its shape is provider-specific
StatusMeaningWhat to do
NOT_STARTThe row exists but upstream has not been polled yetKeep polling
SUBMITTED / QUEUEDAccepted, waiting in the provider’s queueKeep polling
IN_PROGRESSGeneratingKeep polling
SUCCESSTerminal successDownload the video
FAILURETerminal failureRead fail_reason; the reserved amount has already been refunded

Only SUCCESS is terminal-success; FAILURE is terminal-failure and the reserved amount has already been refunded when you see it. Everything else means keep polling.

import os
import time
import requests
BASE = "https://api.routeapi.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['ROUTEAPI_KEY']}"}
task_id = requests.post(
f"{BASE}/v1/video/generations",
headers=HEADERS,
json={
"model": "seedance-2.0-fast",
"prompt": "An orange cat stretching on a windowsill at sunrise",
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
},
timeout=60,
).json()["task_id"]
while True:
task = requests.get(f"{BASE}/v1/video/generations/{task_id}", headers=HEADERS, timeout=30).json()["data"]
print(task["status"], task["progress"])
if task["status"] == "SUCCESS":
video = requests.get(f"{BASE}/v1/videos/{task_id}/content", headers=HEADERS, timeout=300)
video.raise_for_status()
with open(f"{task_id}.mp4", "wb") as f:
f.write(video.content)
break
if task["status"] == "FAILURE":
raise SystemExit(f"task failed: {task['fail_reason']}")
time.sleep(15)
#!/usr/bin/env bash
set -euo pipefail
: "${ROUTEAPI_KEY:?set ROUTEAPI_KEY first}"
BASE="${ROUTEAPI_BASE:-https://api.routeapi.ai}"
AUTH="Authorization: Bearer $ROUTEAPI_KEY"
TASK_ID=$(curl -sS -X POST "$BASE/v1/video/generations" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"model":"seedance-2.0-fast","prompt":"An orange cat stretching on a windowsill at sunrise","duration":4,"resolution":"480p","ratio":"16:9"}' \
| jq -er .task_id)
echo "task: $TASK_ID"
for _ in $(seq 1 60); do
RESP=$(curl -sS "$BASE/v1/video/generations/$TASK_ID" -H "$AUTH")
STATUS=$(echo "$RESP" | jq -r .data.status)
echo "status: $STATUS $(echo "$RESP" | jq -r .data.progress)"
case "$STATUS" in
SUCCESS)
curl -sSL -o "$TASK_ID.mp4" "$BASE/v1/videos/$TASK_ID/content" -H "$AUTH"
echo "saved $TASK_ID.mp4"
exit 0
;;
FAILURE)
echo "failed: $(echo "$RESP" | jq -r .data.fail_reason)"
exit 1
;;
esac
sleep 15
done
echo "timed out waiting for the task"
exit 1

Polling GET /v1/video/generations/{task_id} normally just reads the local task record, so keep the interval at 10–15 seconds rather than hammering the endpoint.

GET /v1/videos/{task_id}/content

Streams the video bytes through RouteAPI, so the caller does not need to reach the provider’s storage. The response carries Cache-Control: public, max-age=86400 and the upstream Content-Type (defaulting to video/mp4 for inline Base64 results).

Terminal window
curl -L -o out.mp4 \
https://api.routeapi.ai/v1/videos/task_G2RdWGt4t1nck5fYqTjwREKJo8Ze4RAV/content \
-H "Authorization: Bearer $ROUTEAPI_KEY"

This route accepts either an API Key or a console session, and it only returns data for tasks owned by the caller. Its errors use the {"error": {"message": "...", "type": "..."}} object shape:

StatusMeaning
400The task is not finished yet; the message contains the current status
404Unknown task, or a task that belongs to another account
403The resolved video URL was rejected by the outbound protection rules
500The task row or its channel could not be read, or the video URL could not be parsed
502The provider could not be reached, returned a non-200 status, or the video URL was empty
StatusCodeMeaning
400task_not_existThe task_id is unknown or belongs to another account
500get_task_failedRouteAPI could not read its own task row
500marshal_response_failed, copy_response_body_failedRouteAPI could not serialize or write the response

Requests rejected before routing use the standard middleware error body {"error": {"message": ..., "type": "error", "code": ...}}, not the task shape.

  • Create a video task — submit a task and the shared request envelope.
  • OpenAI video format — the /v1/videos dialect of the same task, with remix.
  • Assets — a 404 from the asset API means the account has no asset space yet.
  • Common Errors — status codes shared by all model endpoints.