> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mixroute.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Query Video Task

> Query the status and results of a video generation task

Query a submitted MixRoute video task with the task ID returned by the creation endpoint. All family pages use this common polling workflow.

`GET https://api.mixroute.ai/v1/video/generations/{task_id}`

<ParamField path="task_id" type="string" required>
  The MixRoute task ID from submission.
</ParamField>

```bash theme={null}
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, inside `data`, 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](/api-reference/endpoint/wan). |
| Sora 2 | [Download Video](/api-reference/endpoint/download-video) |

Use the actual response from your route. A client that checks only `response.status` or only `response.url` can miss wrapped success and results.

### Example: wrapped success

```json theme={null}
{
  "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.

```python theme={null}
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"))
```

Poll about every 10 seconds; back off on rate limits or transient server errors. Download outputs promptly.

[Seedance](/api-reference/endpoint/seedance) | [Doubao](/api-reference/endpoint/doubao) | [Dreamina](/api-reference/endpoint/dreamina) | [Veo](/api-reference/endpoint/veo) | [MiniMax H3](/api-reference/endpoint/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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.