One project key
Use the same Jevrouter key for chat, images and videos. Choose the exact model in the request body.
Video model guide · Updated October 7, 2026
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.
Use the same Jevrouter key for chat, images and videos. Choose the exact model in the request body.
Set a maximum reservation for each task and choose which models your key can access.
Retrieve progress, outputs and the settled bill. Retrying with the same idempotency key keeps the original task.
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 →
| Endpoint | Task | Published options |
|---|---|---|
| Wan 2.2 · animate 2 | Motion control | resolution: 480p, 720p |
| Wan 2.2 · animate | Motion control | resolution: 480p, 720p |
| Wan 2.2 · fun control | Motion control | resolution: 480p, 720p |
| Wan 2.2 · Image to Video 480p LoRA ultra fast | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 480p LoRA | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 480p ultra fast | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 480p | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 5b 720p LoRA | Image to video | See model parameters |
| Wan 2.2 · Image to Video 5b 720p | Image to video | See model parameters |
| Wan 2.2 · Image to Video 720p LoRA ultra fast | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 720p LoRA | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 720p ultra fast | Image to video | duration: 5, 8 |
| Wan 2.2 · Image to Video 720p | Image to video | duration: 5, 8 |
| Wan 2.2 · image to video LoRA | Image to video | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 · image to video | Image to video | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 · speech to video | Digital human | resolution: 480p, 720p |
| Wan 2.2 spicy · image to video LoRA | Image to video | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 spicy · image to video | Image to video | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 spicy · video extend LoRA | Video extend | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 spicy · video extend | Video extend | duration: 5, 8 · resolution: 480p, 720p |
| Wan 2.2 · Text to Video 480p LoRA ultra fast | Text to video | duration: 5, 8 · size: 832*480, 480*832 |
| Wan 2.2 · Text to Video 480p LoRA | Text to video | duration: 5, 8 · size: 832*480, 480*832 |
| Wan 2.2 · Text to Video 480p | Text to video | duration: 5, 8 · size: 832*480, 480*832 |
| Wan 2.2 · Text to Video 5b 720p LoRA | Text to video | size: 1280*720, 720*1280 |
| Wan 2.2 · Text to Video 5b 720p | Text to video | size: 1280*720, 720*1280 |
| Wan 2.2 · Text to Video 720p LoRA ultra fast | Text to video | duration: 5, 8 · size: 1280*720, 720*1280 |
| Wan 2.2 · Text to Video 720p LoRA | Text to video | duration: 5, 8 · size: 1280*720, 720*1280 |
| Wan 2.2 · Text to Video 720p ultra fast | Text to video | duration: 5, 8 · size: 1280*720, 720*1280 |
| Wan 2.2 · Text to Video 720p | Text to video | duration: 5, 8 · size: 1280*720, 720*1280 |
| Wan 2.2 · video edit | Video to video | resolution: 480p, 720p |
| Wan 2.2 Text-to-Video · 480p Ultra Fast | Text to video | duration: 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.
USD per generated video, for the exact inputs below. Live quotes checked (UTC+8). These dated examples are not a price guarantee.
| Duration | Size | Reserve up to | Estimate |
|---|---|---|---|
| 5s | 832 × 480 | $0.05 | $0.035 |
| 8s | 832 × 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.
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.
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"
}
}
JSONSave 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 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.
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 →
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.
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 →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.