Skip to content

Video generation

Video generation is asynchronous: a clip takes longer than a chat reply, so instead of blocking, the API returns a task that you submit, poll, and download.

Video models are listed in GET /v1/models alongside chat models. Filter for entries whose output_modalities includes video, and check their pricing — video is billed per second of output, not per token. The vendor/ prefix in the console is for browsing only; it is not part of the model id you send to the API.

  1. POST /v1/video/generations — submit the job and receive a task_id.
  2. GET /v1/video/generations/{task_id} — poll until status is completed or failed.
  3. Download the MP4 from the url in the completed task.
import os
import time
import requests
BASE = "https://api.mirapi.ai/v1"
headers = {"Authorization": f"Bearer {os.environ['MIRAPI_API_KEY']}"}
# Step 1: submit
resp = requests.post(
f"{BASE}/video/generations",
headers=headers,
json={
"model": "deepseek-chat",
"prompt": "A golden retriever playing fetch on a sunny beach",
"duration": 5,
"width": 1280,
"height": 720,
"fps": 30,
},
)
resp.raise_for_status()
task_id = resp.json()["task_id"]
# Step 2: poll
while True:
task = requests.get(f"{BASE}/video/generations/{task_id}", headers=headers).json()
if task["status"] in ("completed", "failed"):
break
time.sleep(10)
if task["status"] == "failed":
raise SystemExit(f"Video failed: {task.get('error')}")
# Step 3: download
video = requests.get(task["url"])
open("output.mp4", "wb").write(video.content)
Terminal window
# Step 1
curl -X POST https://api.mirapi.ai/v1/video/generations \
-H "Authorization: Bearer $MIRAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "deepseek-chat", "prompt": "A city skyline at dusk", "duration": 5}'
# Step 2 — repeat until "completed"
curl https://api.mirapi.ai/v1/video/generations/abcd1234efgh \
-H "Authorization: Bearer $MIRAPI_API_KEY"
# Step 3 — download the URL from the completed task
curl -o output.mp4 "https://…"

The completed task’s url is a temporary link — download it right away, before it expires.

The unified route takes a JSON body with these fields:

Parameter Type Required Description
model string yes Video-capable model id from the catalogue.
prompt string yes Text description of the clip.
image string no First-frame image for image-to-video: HTTP(S) URL or base64 data URI.
duration number no Target length in seconds.
width integer no Output width in pixels.
height integer no Output height in pixels.
fps integer no Frame rate.
seed integer no Seed for reproducible output (not guaranteed by every model).
n integer no Number of videos to generate.
response_format string no Response format (e.g. url).
user string no End-user identifier for abuse tracking.
metadata object no Model-specific extras (negative_prompt, style, quality_level, …) where the model accepts them.

status is one of queued, in_progress, completed, failed. A completed task includes the video url, format (e.g. mp4), and a metadata object with the actual duration, width, height, and fps; a failed task includes an error with a code and message.

{
"task_id": "abcd1234efgh",
"status": "completed",
"url": "https://…",
"format": "mp4",
"metadata": { "duration": 5, "width": 1280, "height": 720 }
}

Poll every 10–30 seconds — a job can take minutes, depending on the model and resolution.

Pass an optional image field (URL or base64 data URI) to control the first frame. The model keeps the composition, so describe the motion in prompt rather than re-describing the scene:

resp = requests.post(
f"{BASE}/video/generations",
headers=headers,
json={
"model": "deepseek-chat",
"prompt": "The photo comes to life and the person waves",
"image": "https://example.com/first-frame.png",
"duration": 5,
},
)

MirAPI exposes four route families for video. They all follow the same submit → poll → download flow, but differ in request format and response shape.

  • POST /v1/videosmultipart/form-data with model, prompt, seconds (a string), and an optional input_reference image file. Returns an id (not task_id).
  • GET /v1/videos/{task_id} — task status, including progress and created_at.
  • GET /v1/videos/{task_id}/content — the finished file, returned as video/mp4.
  • POST /v1/video/generations — JSON body (the request parameters above). Returns task_id and status.
  • GET /v1/video/generations/{task_id} — status; a completed task carries url, format, and metadata.
  • POST /kling/v1/videos/text2video and POST /kling/v1/videos/image2video — the same JSON body as the unified route; the image variant takes image.
  • Poll via GET /kling/v1/videos/text2video/{task_id} and GET /kling/v1/videos/image2video/{task_id}.
  • POST /jimeng/ — the native Jimeng API. Action and Version are query parameters: Action is CVSync2AsyncSubmitTask (submit) or CVSync2AsyncGetResult (fetch result), and Version is the API version (e.g. 2022-08-31). The JSON body carries req_key, prompt, and an optional binary_data_base64 image array.

Video is billed per second of generated output, settled when the job completes. Failed jobs produce no output and are not charged.

  • Balance exhausted → the request fails with 403; top up in the console and the same key recovers immediately.
  • Reconcile spend in the console billing log, GET /api/usage/token (account-level summary), or GET /api/log/token (per-request detail).
Status Meaning What to do
400 Invalid parameters Check the model id, and that duration/width/height are numeric.
401 Missing or invalid key Verify Authorization: Bearer.
403 Key valid but rejected Top up (empty balance), or check the model whitelist, quota, and IP allowlist.
404 Task or content not found The task does not exist, or the video is not completed yet.
429 Rate limited Back off exponentially (1s → 2s → 4s, cap ~30s); there is no Retry-After header.
500 Gateway or upstream failure Retry idempotent requests safely.

Every error message ends with a request ID — include it in support tickets.

  • Task stays queued or in_progress for a while — normal; jobs can take minutes. Keep polling at a steady interval.
  • Generation failed — read the error field, confirm the model has video output, and check that any reference image is reachable and in a supported format.
  • 404 on the content endpoint — the task is not completed yet; poll the status endpoint first.