Query Video Task
curl --request GET \
--url https://api.mixroute.ai/v1/video/generations/{task_id}import requests
url = "https://api.mixroute.ai/v1/video/generations/{task_id}"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.mixroute.ai/v1/video/generations/{task_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/video/generations/{task_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/video/generations/{task_id}"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.mixroute.ai/v1/video/generations/{task_id}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/video/generations/{task_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyVideo Series
Query Video Task
Query the status and results of a video generation task
GET
/
v1
/
video
/
generations
/
{task_id}
Query Video Task
curl --request GET \
--url https://api.mixroute.ai/v1/video/generations/{task_id}import requests
url = "https://api.mixroute.ai/v1/video/generations/{task_id}"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.mixroute.ai/v1/video/generations/{task_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/video/generations/{task_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/video/generations/{task_id}"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.mixroute.ai/v1/video/generations/{task_id}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/video/generations/{task_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyQuery a submitted MixRoute video task with the task ID returned by the creation endpoint. All family pages use this common polling workflow.
Use the actual response from your route. A client that checks only
Poll about every 10 seconds; back off on rate limits or transient server errors. Download outputs promptly.
Seedance | Doubao | Dreamina | Veo | MiniMax H3
For Wan, poll about every 15 seconds. A failed task may contain failure text in result_url; never treat that field as a downloadable URL until status is SUCCESS.
GET https://api.mixroute.ai/v1/video/generations/{task_id}
string
required
The MixRoute task ID from submission.
curl "https://api.mixroute.ai/v1/video/generations/TASK_ID" \
--header "Authorization: Bearer $MIXROUTE_API_KEY"
Response and Status
Routes may return the task at the top level, insidedata, or inside a vendor task object. Normalize status case before comparison. These layouts are alternatives, not fields that every response must contain.
| State | Values | Action |
|---|---|---|
| Waiting | queued, pending, submitted, NOT_START | Continue polling. |
| Running | running, in_progress | Continue polling. |
| Succeeded | succeeded, SUCCESS, completed | Read the result object and download the output. |
| Terminal failure | failed, FAILURE, expired, cancelled, canceled | Stop polling and inspect error/fail_reason. |
Result Locations
| Response layout | Video location |
|---|---|
| MixRoute wrapper | data.result_url / data.url |
| Direct task | url / result_url |
| Seedance native result | content.video_url inside the task (for example data.data.content.video_url). |
| MiniMax H3 result | data.result_url or data.data.task.content.video_url in the task envelope; native vendor responses may use task.content.url. |
| Veo native result | Inspect all returned samples/videos. Native Google results can contain video URIs or encoded data rather than one top-level URL. |
| Wan | data.result_url after SUCCESS; native output and usage in data.data. Wan details. |
| Sora 2 | Download Video |
response.status or only response.url can miss wrapped success and results.
Example: wrapped success
{
"code": "success",
"message": "",
"data": {
"task_id": "TASK_ID",
"status": "SUCCESS",
"result_url": "https://example.com/generated-video.mp4"
}
}
Polling Example
This example checks HTTP and application errors, handles common wrappers, stops on terminal states, and applies a client deadline. It returns the task object so the caller can process the route-specific output fields.import os
import time
from urllib.parse import quote
import requests
def unpack_task(payload):
task = payload
for _ in range(6):
if not isinstance(task, dict):
raise ValueError("Unexpected task response")
if task.get("error"):
raise RuntimeError(task["error"])
code = task.get("code")
if code not in (None, 0, 200, "0", "200", "success"):
raise RuntimeError(task.get("message") or task)
if task.get("status"):
return str(task["status"]).lower(), task
nested = task.get("task")
if not isinstance(nested, dict):
nested = task.get("data")
if not isinstance(nested, dict):
break
task = nested
raise ValueError("Task status is missing from the response")
def wait_for_video(task_id, timeout_seconds=1200):
deadline = time.monotonic() + timeout_seconds
url = "https://api.mixroute.ai/v1/video/generations/" + quote(task_id, safe="")
delay = 10
pending = {"queued", "pending", "submitted", "not_start", "running", "in_progress"}
terminal = {"failed", "failure", "expired", "cancelled", "canceled"}
with requests.Session() as session:
session.headers["Authorization"] = "Bearer " + os.environ["MIXROUTE_API_KEY"]
while time.monotonic() < deadline:
remaining = deadline - time.monotonic()
if remaining <= 0:
break
response = session.get(url, timeout=min(30, remaining))
if response.status_code in (429, 500, 502, 503, 504):
delay = min(delay * 2, 30)
else:
response.raise_for_status()
status, task = unpack_task(response.json())
if status in {"success", "succeeded", "completed"}:
return task
if status in terminal:
raise RuntimeError(task.get("fail_reason") or task.get("error") or task)
if status not in pending:
raise ValueError("Unknown task status: " + status)
delay = 10
remaining = deadline - time.monotonic()
if remaining <= 0:
break
time.sleep(min(delay, remaining))
raise TimeoutError("Video task did not finish before the client deadline")
if __name__ == "__main__":
print(wait_for_video("TASK_ID"))