> ## 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.

# Wan

> Wan 3.0, 2.7, and 2.6 video generation, reference inputs, editing, and asynchronous task handling.

Wan uses one MixRoute video endpoint. Keep model at the root and place the provider input and parameters objects inside metadata. Model versions use different input protocols; choose the exact ID and schema below.

`POST https://api.mixroute.ai/v1/video/generations`

## Models

| Model ID                                                   | Mode                        | Resolution          | Duration (seconds)                  |
| ---------------------------------------------------------- | --------------------------- | ------------------- | ----------------------------------- |
| [wan3.0-video](/en/model-api/alibaba/wan3.0-video)         | All-in-One Video Generation | 480P / 720P / 1080P | 2-30 / -1                           |
| [wan2.7-t2v](/en/model-api/alibaba/wan2.7-t2v)             | Text-to-Video               | 720P / 1080P        | 2-15                                |
| [wan2.7-i2v](/en/model-api/alibaba/wan2.7-i2v)             | Image-to-Video              | 720P / 1080P        | 2-15                                |
| [wan2.7-r2v](/en/model-api/alibaba/wan2.7-r2v)             | Reference-to-Video          | 720P / 1080P        | 2-15 (no video) / 2-10 (with video) |
| [wan2.7-videoedit](/en/model-api/alibaba/wan2.7-videoedit) | Video Editing               | 720P / 1080P        | 2-10                                |
| [wan2.6-t2v](/en/model-api/alibaba/wan2.6-t2v)             | Text-to-Video               | 720P / 1080P        | 2-15                                |
| [wan2.6-i2v](/en/model-api/alibaba/wan2.6-i2v)             | Image-to-Video              | 720P / 1080P        | 2-15                                |
| [wan2.6-r2v](/en/model-api/alibaba/wan2.6-r2v)             | Reference-to-Video          | 720P / 1080P        | 2-10                                |

Model availability depends on your account's [model list](/en/api-reference/endpoint/list-models). A vendor model or dated snapshot not returned by your account should not be assumed available.

## Request Envelope

| Field                 | Type   | Required | Description                                                                      |
| --------------------- | ------ | -------- | -------------------------------------------------------------------------------- |
| `model`               | string | Yes      | Exact MixRoute model ID.                                                         |
| `metadata`            | object | Yes      | Container for the provider request body, excluding model.                        |
| `metadata.input`      | object | Yes      | Native input object. Prompt and media requirements depend on the selected model. |
| `metadata.parameters` | object | No       | Native generation settings. Preserve their field names and nesting.              |

<Info>
  Authenticate with Authorization: Bearer and your MixRoute key. No Alibaba key, workspace ID, regional endpoint, or X-DashScope-Async header is needed. Do not send input/parameters at the root or flatten their contents directly into metadata.
</Info>

Use metadata.input.prompt for the prompt. Compatibility fallbacks are metadata.prompt, then top-level prompt, in that order; when present, metadata.input.prompt takes precedence. Supply a prompt or valid media input, and obey the selected model's own required-input rules.

Native fields are forwarded without renaming. New provider fields may be supplied in their original input/parameters location; the upstream service validates model-specific combinations. This does not make a field supported by every model.

## Wan 3.0

| Field                               | Type      | Required | Description                                                                                                                                                                   |
| ----------------------------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata.input.prompt`             | string    | By mode  | Text instruction, at most 20000 characters; excess text is truncated. Required unless media is supplied.                                                                      |
| `metadata.input.media`              | object\[] | By mode  | Media items; required unless prompt is supplied. Use the combinations below.                                                                                                  |
| `metadata.input.media[].type`       | string    | By mode  | Required per item: first\_frame, last\_frame, reference\_image, reference\_video, reference\_audio, file, or link.                                                            |
| `metadata.input.media[].url`        | string    | By mode  | Required per item. Public HTTP/HTTPS URL; supported images may use a Base64 data URI. Native OSS resources must be accessible to the route account.                           |
| `metadata.parameters.resolution`    | string    | No       | 480P, 720P, or 1080P. MixRoute explicitly fills 1080P when omitted.                                                                                                           |
| `metadata.parameters.ratio`         | string    | No       | adaptive (default), 16:9, 4:3, 1:1, 3:4, or 9:16. Use adaptive for extension.                                                                                                 |
| `metadata.parameters.duration`      | integer   | No       | Default 5. Without source video: 2-30 seconds. With video: total source-video duration plus generated duration must not exceed 30 seconds. -1 selects duration automatically. |
| `metadata.parameters.audio`         | boolean   | No       | Default true. false produces video without an audio track.                                                                                                                    |
| `metadata.parameters.seed`          | integer   | No       | -1 or 0-2147483647. -1 or omission selects a random seed; repeatability is not guaranteed.                                                                                    |
| `metadata.parameters.prompt_extend` | boolean   | No       | Prompt rewriting; default true.                                                                                                                                               |
| `metadata.parameters.watermark`     | boolean   | No       | Add an AI watermark; default false.                                                                                                                                           |

### Media Types

| type                         | Limit / Usage                                                                              |
| ---------------------------- | ------------------------------------------------------------------------------------------ |
| `first_frame` / `last_frame` | At most one of each; first frame alone or first+last frame. Do not use a last frame alone. |
| `reference_image`            | Up to 10 images.                                                                           |
| `reference_video`            | Up to five videos, 1-15 seconds each, at most 15 seconds total.                            |
| `reference_audio`            | Up to five audio clips, 1-15 seconds each, at most 15 seconds total.                       |
| `file`                       | One public document, at most 100 MB and 50 pages for paginated formats.                    |
| `link`                       | One publicly accessible webpage that does not require login.                               |

* Frame mode (first\_frame/last\_frame) is mutually exclusive with reference\_\*, file, and link. Unlike Wan 2.7 I2V, Wan 3.0 frame mode cannot include driving audio.
* Reference images, videos, and audio may be combined. file and link are mutually exclusive, but either may accompany reference\_\* media. Respect every per-type limit and the overall limit of 20 media items.
* Refer to media by type-specific order: Image 1, Video 1, Audio 1, or 图1、视频1、音频1.
* Editing/extension require reference\_video and a matching prompt. Use ratio=adaptive for extension; for editing, adaptive and duration=-1 preserve source framing and let the model choose the duration. Input video time plus output time must still fit within 30 seconds.

<Note>
  Wan 3.0 does not use size, negative\_prompt, template, img\_url, first\_frame\_url, last\_frame\_url, or audio\_url. The gateway removes legacy fields and can convert audio\_url to a reference\_audio item. New requests should use input.media directly.
</Note>

## Wan 2.7

| Field                                    | Type      | Required | Description                                                                                                                                                                                                                             |
| ---------------------------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata.input.prompt`                  | string    | By mode  | Up to 5000 characters, with excess truncated. Required for T2V/R2V; optional for I2V/VideoEdit when required media is present.                                                                                                          |
| `metadata.input.negative_prompt`         | string    | No       | Content to exclude; at most 500 characters, with excess truncated.                                                                                                                                                                      |
| `metadata.input.audio_url`               | string    | No       | T2V only: driving audio URL, WAV/MP3, 2-30 seconds, at most 15 MB. Long audio is trimmed; a short clip leaves a silent tail.                                                                                                            |
| `metadata.input.media`                   | object\[] | By mode  | Required for I2V, R2V, and VideoEdit. Each mode has different item types and combinations.                                                                                                                                              |
| `metadata.input.media[].type`            | string    | By mode  | Required per media item; use the model-specific types below.                                                                                                                                                                            |
| `metadata.input.media[].url`             | string    | By mode  | Required per media item. Public HTTP/HTTPS URL; image inputs also support data:image/...;base64,... . Accessible native OSS references are supported.                                                                                   |
| `metadata.input.media[].reference_voice` | string    | No       | R2V reference\_image/reference\_video only: voice-timbre reference URL, WAV/MP3, 1-10 seconds, at most 15 MB. Overrides the reference video voice.                                                                                      |
| `metadata.parameters.resolution`         | string    | No       | 720P or 1080P (default), with exact capitalization.                                                                                                                                                                                     |
| `metadata.parameters.ratio`              | string    | No       | T2V/R2V/VideoEdit: 16:9, 9:16, 1:1, 4:3, or 3:4. T2V/R2V default to 16:9; R2V ignores ratio when a first frame is supplied. VideoEdit follows its source when omitted. I2V follows its image/video input and does not use this setting. |
| `metadata.parameters.duration`           | integer   | No       | T2V/I2V: 2-15 seconds, default 5. R2V: 2-15 without video references, 2-10 with video, default 5. VideoEdit: omit to retain source length; 2-10 trims from the start.                                                                   |
| `metadata.parameters.audio_setting`      | string    | No       | VideoEdit only: auto (default) lets the prompt guide audio handling; origin preserves source audio.                                                                                                                                     |
| `metadata.parameters.prompt_extend`      | boolean   | No       | Prompt rewriting; default true.                                                                                                                                                                                                         |
| `metadata.parameters.watermark`          | boolean   | No       | Add an AI watermark; default false.                                                                                                                                                                                                     |
| `metadata.parameters.seed`               | integer   | No       | 0-2147483647; omitted means random. Identical seeds do not guarantee identical output.                                                                                                                                                  |

### Input Modes

| Model              | Media Rules                                                                                                                                                                            |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wan2.7-t2v`       | prompt plus optional input.audio\_url; no media array.                                                                                                                                 |
| `wan2.7-i2v`       | first\_frame; first\_frame+driving\_audio; first\_frame+last\_frame; first\_frame+last\_frame+driving\_audio; first\_clip; or first\_clip+last\_frame. Each type appears at most once. |
| `wan2.7-r2v`       | 1-5 reference\_image/reference\_video items total, optionally one first\_frame. reference\_voice belongs to each reference item, not a separate media type.                            |
| `wan2.7-videoedit` | Exactly one video item (type=video), optionally up to four reference\_image items.                                                                                                     |

For I2V continuation with first\_clip, duration controls the final total length including the source clip, not just the added seconds. For R2V, use Image 1 / Video 1 references, counting images and videos separately. Wan 2.7 uses resolution/ratio rather than the Wan 2.6 T2V/R2V size field; shot\_type is no longer used. I2V output follows the source aspect ratio and omits ratio.

## Wan 2.6

| Field                                 | Type      | Required | Description                                                                                                                                                           |
| ------------------------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `metadata.input.prompt`               | string    | By mode  | At most 1500 characters, with excess truncated. Required for T2V/R2V; optional for I2V with a source image. R2V references use character1, character2, etc.           |
| `metadata.input.negative_prompt`      | string    | No       | Content to exclude; at most 500 characters, with excess truncated.                                                                                                    |
| `metadata.input.img_url`              | string    | By mode  | I2V only, required: first-frame image URL or image Base64 data URI.                                                                                                   |
| `metadata.input.audio_url`            | string    | No       | T2V/I2V only: driving audio URL, WAV/MP3, 2-30 seconds, at most 15 MB.                                                                                                |
| `metadata.input.reference_urls`       | string\[] | By mode  | R2V only, required: 1-5 source URLs, at most five images and three videos, with at most five total. Each source identifies one subject.                               |
| `metadata.input.reference_video_urls` | string\[] | No       | Deprecated R2V video-only input, at most three videos. Prefer reference\_urls; do not mix both formats.                                                               |
| `metadata.parameters.size`            | string    | No       | T2V/R2V only: `width*height` from the size table; default `1920*1080`.                                                                                                |
| `metadata.parameters.resolution`      | string    | No       | I2V only: 720P or 1080P (default). The aspect ratio follows the first-frame image.                                                                                    |
| `metadata.parameters.duration`        | integer   | No       | T2V/I2V: 2-15 seconds; R2V: 2-10 seconds. Default 5.                                                                                                                  |
| `metadata.parameters.prompt_extend`   | boolean   | No       | T2V/I2V only: prompt rewriting, default true. Not an R2V setting.                                                                                                     |
| `metadata.parameters.shot_type`       | string    | No       | single (default) or multi. For T2V/I2V, effective only when prompt\_extend=true. R2V uses this field directly. Takes precedence over shot instructions in the prompt. |
| `metadata.parameters.watermark`       | boolean   | No       | Add an AI watermark; default false.                                                                                                                                   |
| `metadata.parameters.seed`            | integer   | No       | 0-2147483647; omitted means random. Identical seeds do not guarantee identical output.                                                                                |

### T2V / R2V Sizes

| Tier  | Allowed size Values                                             |
| ----- | --------------------------------------------------------------- |
| 720P  | `1280*720`, `720*1280`, `960*960`, `1088*832`, `832*1088`       |
| 1080P | `1920*1080`, `1080*1920`, `1440*1440`, `1632*1248`, `1248*1632` |

Wan 2.6 R2V uses character1, character2, etc., in reference\_urls order, rather than the Wan 2.7 Image/Video labels. Its references require public HTTP/HTTPS or accessible OSS URLs. The standard 2.6 models listed here do not expose the audio=false switch of the separate Flash variants. Legacy effect templates are not a common capability of these eight models.

## Media Constraints

| Input                   | Constraints                                                                                                                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Images                  | JPEG/JPG, PNG without transparency, BMP, WebP; 240-8000 px per edge, at most 20 MB. Wan 3.0/2.7 additionally limit the long/short ratio to 8:1.                                     |
| Wan 3.0 reference video | MP4/MOV; 1-15 seconds each, total at most 15 seconds; at least 16 fps; 240-4096 px per edge; ratio up to 8:1; at most 100 MB per file.                                              |
| Wan 2.7 video           | MP4/MOV; 240-4096 px per edge, ratio up to 8:1, at most 100 MB. first\_clip/VideoEdit source: 2-10 seconds. R2V reference: 1-30 seconds.                                            |
| Wan 2.6 R2V video       | reference\_urls: MP4/MOV, 1-30 seconds, at most 100 MB. The deprecated reference\_video\_urls format requires 2-30 seconds.                                                         |
| Audio                   | WAV/MP3, at most 15 MB each. Wan 3.0 reference audio: 1-15 seconds, total at most 15. Wan 2.7 reference\_voice: 1-10 seconds. T2V driving audio / I2V driving\_audio: 2-30 seconds. |
| Wan 3.0 files           | docx, doc, xlsx, xls, pptx, ppt, pdf, txt, key, pages, numbers, md; at most 100 MB. PDF/Word/PowerPoint/Keynote/Pages documents: at most 50 pages.                                  |

Use public URLs for portable requests. OSS temporary links and provider asset IDs are scoped to the upstream account/region and must be accessible to the selected channel. Do not send your MixRoute key when fetching a third-party CDN result URL.

## Request Examples

Set MIXROUTE\_API\_KEY and replace example.com media URLs with accessible source files. Each POST creates a separate task; do not automatically repeat a timed-out submission.

### Wan 3.0 Video

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan3.0-video",
  "metadata": {
    "input": {
      "prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
    },
    "parameters": {
      "resolution": "480P",
      "ratio": "16:9",
      "duration": 2,
      "audio": false,
      "prompt_extend": false,
      "watermark": false
    }
  }
}'
```

### Wan 2.7 T2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.7-t2v",
  "metadata": {
    "input": {
      "prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
    },
    "parameters": {
      "resolution": "720P",
      "ratio": "9:16",
      "duration": 2,
      "prompt_extend": false,
      "watermark": false
    }
  }
}'
```

### Wan 2.7 I2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.7-i2v",
  "metadata": {
    "input": {
      "prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting.",
      "media": [
        {
          "type": "first_frame",
          "url": "https://example.com/reference.png"
        }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "duration": 2,
      "prompt_extend": false,
      "watermark": false
    }
  }
}'
```

### Wan 2.7 R2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.7-r2v",
  "metadata": {
    "input": {
      "prompt": "Image 1 slowly rotates on a white tabletop. Static camera, soft studio lighting.",
      "media": [
        {
          "type": "reference_image",
          "url": "https://example.com/reference.png"
        }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "ratio": "1:1",
      "duration": 2,
      "watermark": false
    }
  }
}'
```

### Wan 2.7 VideoEdit

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.7-videoedit",
  "metadata": {
    "input": {
      "prompt": "Change the mug color to blue while preserving the original motion and white tabletop.",
      "media": [
        {
          "type": "video",
          "url": "https://example.com/source.mp4"
        }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "duration": 2,
      "watermark": false
    }
  }
}'
```

### Wan 2.6 T2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.6-t2v",
  "metadata": {
    "input": {
      "prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting."
    },
    "parameters": {
      "size": "1280*720",
      "duration": 2,
      "prompt_extend": false,
      "watermark": false
    }
  }
}'
```

### Wan 2.6 I2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.6-i2v",
  "metadata": {
    "input": {
      "prompt": "A red ceramic mug slowly rotates on a white tabletop. Static camera, soft studio lighting.",
      "img_url": "https://example.com/reference.png"
    },
    "parameters": {
      "resolution": "720P",
      "duration": 2,
      "prompt_extend": false,
      "watermark": false
    }
  }
}'
```

### Wan 2.6 R2V

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.6-r2v",
  "metadata": {
    "input": {
      "prompt": "character1 slowly rotates on a white tabletop. Static camera, soft studio lighting.",
      "reference_urls": [
        "https://example.com/reference.png"
      ]
    },
    "parameters": {
      "size": "1280*720",
      "duration": 2,
      "watermark": false
    }
  }
}'
```

### First and Last Frames

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan2.7-i2v",
  "metadata": {
    "input": {
      "prompt": "A closed gift box slowly opens, revealing a red ceramic mug.",
      "media": [
        {
          "type": "first_frame",
          "url": "https://example.com/first.png"
        },
        {
          "type": "last_frame",
          "url": "https://example.com/last.png"
        }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "duration": 5
    }
  }
}'
```

### File Input Without a Prompt

```bash theme={null}
curl --request POST "https://api.mixroute.ai/v1/video/generations" \
  --header "Authorization: Bearer $MIXROUTE_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
  "model": "wan3.0-video",
  "metadata": {
    "input": {
      "media": [
        {
          "type": "file",
          "url": "https://example.com/product.pptx"
        }
      ]
    },
    "parameters": {
      "resolution": "480P",
      "duration": 5
    }
  }
}'
```

## Responses and Polling

Submission returns a MixRoute task\_id (and id alias). This is not the upstream task ID.

```json theme={null}
{
  "id": "TASK_ID",
  "task_id": "TASK_ID",
  "object": "video",
  "model": "wan3.0-video",
  "status": "queued"
}
```

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

| Gateway Status         | Upstream Status                   | Action                                                     |
| ---------------------- | --------------------------------- | ---------------------------------------------------------- |
| `NOT_START` / `QUEUED` | `PENDING`                         | Wait and query again.                                      |
| `IN_PROGRESS`          | `RUNNING`                         | Continue polling.                                          |
| `SUCCESS`              | `SUCCEEDED`                       | Read data.result\_url.                                     |
| `FAILURE`              | `FAILED` / `CANCELED` / `UNKNOWN` | Stop; inspect data.fail\_reason and the upstream response. |

```json theme={null}
{
  "code": "success",
  "message": "",
  "data": {
    "task_id": "TASK_ID",
    "status": "SUCCESS",
    "progress": "100%",
    "result_url": "https://example.com/generated.mp4",
    "fail_reason": "",
    "data": {
      "request_id": "UPSTREAM_REQUEST_ID",
      "output": {
        "task_id": "UPSTREAM_TASK_ID",
        "task_status": "SUCCEEDED",
        "video_url": "https://example.com/generated.mp4"
      },
      "usage": {
        "output_video_duration": 2,
        "SR": 480,
        "video_count": 1
      }
    }
  }
}
```

<Warning>
  Read result\_url only after SUCCESS. On failure the gateway may place the failure text in result\_url, so it is not necessarily a URL. The code="success" envelope only means the query succeeded, not that the generation succeeded.
</Warning>

The complete upstream result is retained at data.data; read usage and request\_id there. UNKNOWN means the upstream task is missing or expired, not necessarily a generation error. Poll about every 15 seconds and back off on rate limits/transient errors. Upstream task lookup and result links have limited retention, typically 24 hours; save completed output promptly.

## Python Workflow

```python theme={null}
import os
import time
from urllib.parse import quote, urlparse
import requests

BASE_URL = "https://api.mixroute.ai"

def create_video(session, payload):
    response = session.post(BASE_URL + "/v1/video/generations", json=payload, timeout=120)
    response.raise_for_status()
    result = response.json()
    task_id = result.get("task_id") or result.get("id")
    if not task_id:
        raise RuntimeError(result.get("message") or result)
    return task_id

def wait_for_video(session, task_id, timeout_seconds=1200):
    url = BASE_URL + "/v1/video/generations/" + quote(task_id, safe="")
    deadline = time.monotonic() + timeout_seconds
    delay = 15
    while time.monotonic() < deadline:
        remaining = deadline - time.monotonic()
        if remaining <= 0:
            break
        try:
            response = session.get(url, timeout=min(30, remaining))
        except (requests.Timeout, requests.ConnectionError):
            delay = min(delay * 2, 60)
        else:
            if response.status_code in (429, 500, 502, 503, 504):
                delay = min(delay * 2, 60)
            else:
                response.raise_for_status()
                result = response.json()
                if result.get("code") not in (None, 0, 200, "0", "200", "success"):
                    raise RuntimeError(result.get("message") or result)
                task = result.get("data") or {}
                status = str(task.get("status", "")).upper()
                if status == "SUCCESS":
                    video_url = task.get("result_url", "")
                    parsed = urlparse(video_url)
                    if parsed.scheme not in ("http", "https") or not parsed.netloc:
                        raise RuntimeError("Successful task has no valid video URL")
                    return task
                if status in {"FAILURE", "FAILED", "EXPIRED", "CANCELED", "CANCELLED"}:
                    raise RuntimeError(task.get("fail_reason") or task)
                if status not in {"QUEUED", "NOT_START", "PENDING", "IN_PROGRESS", "RUNNING"}:
                    raise RuntimeError("Unknown task status: " + status)
                delay = 15
        remaining = deadline - time.monotonic()
        if remaining <= 0:
            break
        time.sleep(min(delay, remaining))
    raise TimeoutError("Video task is still pending; keep its task ID and query it later")

if __name__ == "__main__":
    payload = {
        "model": "wan3.0-video",
        "metadata": {
            "input": {"prompt": "A red ceramic mug slowly rotates on a white tabletop."},
            "parameters": {"resolution": "480P", "ratio": "16:9", "duration": 2, "audio": False},
        },
    }
    with requests.Session() as session:
        session.headers["Authorization"] = "Bearer " + os.environ["MIXROUTE_API_KEY"]
        task_id = create_video(session, payload)
        print("task_id:", task_id, flush=True)
        task = wait_for_video(session, task_id)
        print(task["result_url"])
        print(task.get("data", {}).get("usage", {}))
```

Use the console bill for final charges. Submission can reserve quota before completion; request estimates and final settlement may differ. Do not treat input/negative/zero duration values as a way to obtain a zero-cost task.
