All video models

Video model guide · Updated October 7, 2026

Wan 2.2 API

Start with a short text-to-video request, or choose a dedicated image-to-video or LoRA variant. Compare the actual input requirements before switching endpoints.

One project key

Use the same Jevrouter key for chat, images and videos. Choose the exact model in the request body.

Bound the spend

Set a maximum reservation for each task and choose which models your key can access.

Keep the task record

Retrieve progress, outputs and the settled bill. Retrying with the same idempotency key keeps the original task.

Which Wan 2.2 endpoint should I choose?

31 currently available variants. Names such as Flash, Pro, 5B and Ultra Fast identify separate variants; they are not interchangeable request parameters. Catalog capabilities below are declarations, not independent performance measurements.

Start with Wan 2.2 Text-to-Video · 480p Ultra Fast →

Compare all 31 variants and their parameters
EndpointTaskPublished options
Wan 2.2 · animate 2Motion controlresolution: 480p, 720p
Wan 2.2 · animateMotion controlresolution: 480p, 720p
Wan 2.2 · fun controlMotion controlresolution: 480p, 720p
Wan 2.2 · Image to Video 480p LoRA ultra fastImage to videoduration: 5, 8
Wan 2.2 · Image to Video 480p LoRAImage to videoduration: 5, 8
Wan 2.2 · Image to Video 480p ultra fastImage to videoduration: 5, 8
Wan 2.2 · Image to Video 480pImage to videoduration: 5, 8
Wan 2.2 · Image to Video 5b 720p LoRAImage to videoSee model parameters
Wan 2.2 · Image to Video 5b 720pImage to videoSee model parameters
Wan 2.2 · Image to Video 720p LoRA ultra fastImage to videoduration: 5, 8
Wan 2.2 · Image to Video 720p LoRAImage to videoduration: 5, 8
Wan 2.2 · Image to Video 720p ultra fastImage to videoduration: 5, 8
Wan 2.2 · Image to Video 720pImage to videoduration: 5, 8
Wan 2.2 · image to video LoRAImage to videoduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 · image to videoImage to videoduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 · speech to videoDigital humanresolution: 480p, 720p
Wan 2.2 spicy · image to video LoRAImage to videoduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 spicy · image to videoImage to videoduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 spicy · video extend LoRAVideo extendduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 spicy · video extendVideo extendduration: 5, 8 · resolution: 480p, 720p
Wan 2.2 · Text to Video 480p LoRA ultra fastText to videoduration: 5, 8 · size: 832*480, 480*832
Wan 2.2 · Text to Video 480p LoRAText to videoduration: 5, 8 · size: 832*480, 480*832
Wan 2.2 · Text to Video 480pText to videoduration: 5, 8 · size: 832*480, 480*832
Wan 2.2 · Text to Video 5b 720p LoRAText to videosize: 1280*720, 720*1280
Wan 2.2 · Text to Video 5b 720pText to videosize: 1280*720, 720*1280
Wan 2.2 · Text to Video 720p LoRA ultra fastText to videoduration: 5, 8 · size: 1280*720, 720*1280
Wan 2.2 · Text to Video 720p LoRAText to videoduration: 5, 8 · size: 1280*720, 720*1280
Wan 2.2 · Text to Video 720p ultra fastText to videoduration: 5, 8 · size: 1280*720, 720*1280
Wan 2.2 · Text to Video 720pText to videoduration: 5, 8 · size: 1280*720, 720*1280
Wan 2.2 · video editVideo to videoresolution: 480p, 720p
Wan 2.2 Text-to-Video · 480p Ultra FastText to videoduration: 5, 8 · size: 832*480, 480*832

Open an endpoint to see required source media, conditional rules and the full parameter schema. Supplying a prompt alone is not sufficient for an image or reference job.

Video API pricing examples

USD per generated video, for the exact inputs below. Live quotes checked (UTC+8). These dated examples are not a price guarantee.

Wan 2.2 text-to-video · 480p Ultra Fast
DurationSizeReserve up toEstimate
5s832 × 480$0.05$0.035
8s832 × 480$0.08$0.056

We reserve the quoted maximum before submission, settle the confirmed generation cost and release the remainder. Set jev.max_cost_usd to bound the reservation. If the current quote exceeds that limit, generation is rejected before it starts.

The estimated charge is not a receipt. Check the settled request record for what you actually paid. Other variants and input combinations require their own quote.

Call the Wan 2.2 API

This example creates one billable five-second text-to-video task with a fixed model and a reservation limit. Allow wan/wan-2.2-t2v-480p-ultra-fast on your key and load it into JEVROUTER_API_KEY. Use either the cURL or Python example for a test; running both creates separate jobs.

Submit with cURL

curl --fail-with-body https://api.jevrouter.io/v1/videos \
+  -H "Authorization: Bearer $JEVROUTER_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Idempotency-Key: my-first-wan22-video" \
+  -d @- <<'JSON'
{
  "model": "wan/wan-2.2-t2v-480p-ultra-fast",
  "input": {
    "prompt": "A yellow sailboat on a quiet lake",
    "duration": 5,
    "size": "832*480"
  },
  "jev": {
    "max_cost_usd": "0.05"
  }
}
JSON

Save data.id. Retrieve GET /v1/videos/REQUEST_ID with the same authorization header, at least three seconds apart, until data.status is completed or failed. Completed results appear in data.outputs. Keep the same idempotency key when recovering an interrupted submission.

Python example: submit, resume and download

Python 3.10+; no extra packages. Save the script as generate_video.py and run it with your key in the environment. It persists video-task.json before submitting, then polls and saves video.mp4. Keep the state file to resume the same job; use a new JEV_VIDEO_STATE filename only for a deliberately new generation. Run one process per state file.

Show the complete Python example
Python
import json
import os
import shutil
import time
import uuid
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import quote, urlsplit
from urllib.request import Request, urlopen

API = "https://api.jevrouter.io/v1/videos"
KEY = os.environ["JEVROUTER_API_KEY"]
STATE = Path(os.environ.get("JEV_VIDEO_STATE", "video-task.json"))

# One state file per intended video. Keep it when retrying or resuming.
# Run only one copy of this script against a state file at a time.
if not STATE.exists():
    with STATE.open("x") as file:
        json.dump({"idempotency_key": str(uuid.uuid4()), "body": {
    "model": "wan/wan-2.2-t2v-480p-ultra-fast",
    "input": {
        "prompt": "A yellow sailboat on a quiet lake",
        "duration": 5,
        "size": "832*480"
    },
    "jev": {
        "max_cost_usd": "0.05"
    }
}}, file)
state = json.loads(STATE.read_text())

def save():
    temporary = STATE.with_name(STATE.name + ".tmp")
    temporary.write_text(json.dumps(state))
    temporary.replace(STATE)

def api(url, body=None):
    headers = {"Authorization": "Bearer " + KEY}
    if body is not None:
        headers.update({"Content-Type": "application/json",
                        "Idempotency-Key": state["idempotency_key"]})
    request = Request(url, data=json.dumps(body).encode() if body is not None else None,
                      headers=headers, method="POST" if body is not None else "GET")
    try:
        with urlopen(request, timeout=90) as response:
            return response.status, json.load(response)
    except HTTPError as error:
        return error.code, json.loads(error.read())
    except (URLError, TimeoutError):
        raise SystemExit("Connection interrupted. Keep the state file and run again to resume.")

if not state.get("request_id"):
    status, result = api(API, state["body"])
    if status == 200:
        state["request_id"] = result["data"]["id"]
    else:
        error = result.get("error", {})
        recoverable = status in (409, 503) and error.get("code") in (
            "request_already_exists", "outcome_unknown")
        request_id = (error.get("details") or {}).get("request_id") or error.get("request_id")
        if not recoverable or not request_id:
            raise SystemExit(result)
        state["request_id"] = request_id
    save()

task_url = API + "/" + quote(state["request_id"], safe="")
print("Task:", state["request_id"])
deadline = time.monotonic() + 900
while time.monotonic() < deadline:
    time.sleep(5)
    status, result = api(task_url)
    error = result.get("error", {})
    if status == 429 or (status in (409, 503) and error.get("code") in (
            "request_already_exists", "outcome_unknown")):
        continue  # Inspect the same task; never submit a replacement.
    if status != 200:
        raise SystemExit(result)
    task = result["data"]
    if task["status"] == "failed":
        raise SystemExit(task.get("error") or "Video generation failed")
    if task["status"] != "completed":
        continue
    print("Outputs:", task["outputs"])
    outputs = task["outputs"]
    if outputs and isinstance(outputs[0], str):
        media_url = outputs[0]
        parts = urlsplit(media_url)
        if parts.scheme != "https" or not parts.hostname or parts.username or parts.password:
            raise SystemExit("Unexpected media URL; inspect outputs manually")
        # Separate media request: NEVER send your Jevrouter key to a media host.
        with urlopen(media_url, timeout=120) as response, open("video.mp4", "wb") as output:
            shutil.copyfileobj(response, output)
        print("Saved video.mp4")
    else:
        print("This model returned structured outputs; inspect the printed result.")
    break
else:
    raise SystemExit("Still pending. Keep the state file and run again to resume.")

Read the full tutorial: status, errors, billing and safe retries →

What we have verified

A five-second, 832 × 480 text-to-video task completed through Jevrouter in our October 7 production check. The reservation was $0.05 and the settled charge was $0.035. The signed completion notification and a retry returning the same task were also verified. This is one integration check, not a quality or latency benchmark.

A model being listed does not mean every variant or option has been independently tested. Start with your own representative inputs before choosing on output quality.

Fixed model or Auto?

Use the explicit model above when you need that particular variant. Use jev/auto and task: "text-to-video" when you want routing among compatible models allowed by your key. Auto must also be enabled on the project and allowed on the key.

Auto checks task type and parameter compatibility, then compares live quotes for up to eight candidates shortlisted by catalog price. It chooses within that shortlist and your limit. It does not promise the best quality or search every possible model. Model-specific input fields can narrow the compatible pool.

Read the video API contract →

Keep your result

Closing your connection does not cancel an accepted job. The platform tracks completion and settlement independently. Results may be ready before billing finishes; inspect the request record for the confirmed charge.

Media links are retained for up to seven days and can expire earlier. Download while available and keep your own copy. Customer callbacks and task cancellation are not supported.