Video Generation Guide
SIRAYA Model Router provides one unified API for all video models. Every model uses the same POST /v1/videos/generations endpoint. By default the request waits for the render and returns the finished video URL; with async: true it returns a job id and you poll for status (or receive a callback) and download the result — what changes per model is only which parameters apply (see Per-model parameter support).
The mode is determined by the parameters you send:
- Text-to-video — send a
prompt. - Image-to-video — add
frame_images(first/last frame) orimage_url. - Reference-guided — add
input_references(image / video / audio).
Talking-head avatar videos and lip-sync use their own endpoints (/v1/avatar/*) rather than
/v1/videos/generations — see Avatar.
https://llm.siraya.ai/v1/videos/generations
Header
Bearer <API_KEY>).
Body
veo-3.1-generate-001, ByteDance-Seedance-1.5-pro).
duration; Kling is the exception — it takes duration and refuses seconds with a 400. An out-of-range value is rejected at submit by some models (Veo, HappyHorse) but only fails after the job starts on others (Seedance), so validate it client-side.
1280x720. A standard size resolves to resolution + aspect_ratio; if you send both, they must agree with size or the request returns a 400.
720p or 1080p. Supported values differ per model; see the Seedance, HappyHorse, MiniMax H3, Kling and Wan model tables and the other model pages. Values are case-sensitive: HappyHorse and Wan 2.7 use uppercase 720P/1080P; MiniMax H3 takes 480P, 768P and 2K; Kling takes lowercase 720p/1080p, plus 4k on kling-3.0 and kling-3.0-omni; Wan 3.0 takes lowercase 480p/720p/1080p, or 1080p/2k/4k on its -pro tiers.
16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Supported values differ per model: Veo takes only 16:9 and 9:16; Seedance and Wan 3.0 also take adaptive; HappyHorse also takes 4:5, 5:4, 9:21; Kling takes only 16:9, 9:16 and 1:1. See the model pages.
audio parameter (see the Kling audio table).
frame_images.
false, the request waits for generation to finish and returns the completed video URL. When true, it returns immediately with a video id you poll for status — recommended for longer videos to avoid request timeouts. See Asynchronous generation.
async is true. An http(s) URL the router will POST to once generation completes (or fails), so you don't have to poll.
import requests
url = "https://llm.siraya.ai/v1/videos/generations"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer <API_KEY>"
}
data = {
"model": "veo-3.1-generate-001",
"prompt": "A cute baby sea otter playing in the water",
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
Example Response
Frame and reference inputs
frame_images
Pin the first and/or last frame of the video (image-to-video). Each item:
| Field | Type | Description |
|---|---|---|
image_url |
string | URL or base64 data URL of the frame image. |
frame_type |
string | first_frame or last_frame. |
Last-frame control support varies by model — see Per-model parameter support.
input_references
Soft-guidance references. Support varies by model (see the matrix). Each item:
| Field | Type | Description |
|---|---|---|
type |
string | image, video, or audio. |
url |
string | URL or base64 data URL. |
role |
string | Optional role hint, e.g. reference_image, reference_video, reference_audio. Veo also reads style. Where a model page documents specific role values, use those. |
Some families key off
rolerather thantype— HappyHorse and Wan, for instance, distinguishreference_imagefrom thevideobeing edited that way, and Wan uses it fordriving_audioandfirst_cliptoo. Where a model page documents specificrolevalues, use those.
Asynchronous generation
Video generation can take a while. By default the request is synchronous — it waits for the render to finish and returns the completed video URL. For longer videos, set async: true to return immediately with a video id, then either poll for status or receive a callback. This avoids request timeouts.
Synchronous mode: errors and timeout
In synchronous mode the router waits up to about 16 minutes for the render. If the job fails, or does not finish in that time, the request returns HTTP 400 with the error message and an empty data:
A 200 at submit does not guarantee success in either mode: some models validate parameters (for example seconds or aspect_ratio combinations) or run content checks only after the job starts, so a request can end as failed — see the Seedance notes.
Submit an async job
curl https://llm.siraya.ai/v1/videos/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"model": "veo-3.1-generate-001",
"prompt": "A cute baby sea otter playing in the water",
"async": true,
"callbackUrl": "https://your-app.com/webhooks/siraya-video"
}'
The job is accepted immediately. status is processing and no URL is returned yet — keep the id to poll status and download the result:
{
"id": "video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31...",
"object": "video",
"status": "processing",
"model": "veo-3.1-generate-001",
"seconds": 8,
"usage": { "completion_tokens": 0, "total_tokens": 0 }
}
Poll status
https://llm.siraya.ai/v1/videos/{video_id}
Call the status endpoint with the id until status is completed (or failed):
{
"id": "video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31...",
"object": "video",
"status": "completed",
"model": "ByteDance-Seedance-1.5-pro",
"seconds": 5,
"resolution": "720p",
"ratio": "16:9",
"output_url": "https://.../out.mp4?...",
"usage": { "completion_tokens": 108900, "total_tokens": 108900 }
}
statusis one ofprocessing,completed, orfailed.output_urlis returned by some models only (it is not returned for Veo). When it is absent, download the video from the/contentendpoint below.- When
failed, anerrorobject ({"code": "...", "message": "..."}) is included instead ofoutput_url. - Poll every few seconds and back off on
429.
Download the video
https://llm.siraya.ai/v1/videos/{video_id}/content
Once status is completed, download the raw video bytes (Content-Type: video/mp4). When the status call returns an output_url, you can fetch that directly instead.
curl https://llm.siraya.ai/v1/videos/<video_id>/content \
-H "Authorization: Bearer <API_KEY>" \
-o output.mp4
Callback (instead of polling)
If you pass a callbackUrl, the router sends a POST to that URL when the job finishes, so you can skip polling. The body is the synchronous response — the finished video under data[].url — plus the job id and a status:
{
"id": "video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31...",
"created": 1779869320,
"status": "completed",
"data": [
{ "url": "https://resources.siraya.ai/v1/videos/.../content" }
],
"error": {}
}
status is completed, failed, or timeout (the job did not finish within about 16 minutes). On failed and timeout, data is empty and error.message carries the reason. The same id is sent in the X-Video-Id request header.
Your endpoint should respond 2xx within 10 seconds. A failed delivery is retried up to 3 more times (4 attempts in total).
Delete a video
https://llm.siraya.ai/v1/videos/{video_id}
Deletes a completed task. Only the Wan 3.0 and Wan Spicy models support it — other models answer
405. A task that is still processing answers 409, and a failed task is refused too.
{
"id": "video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31...",
"object": "video",
"deleted": true,
"deleted_at": "2026-10-21T08:15:02Z",
"model": "wan3.0-video"
}
Video object (status response)
The status endpoint (GET /v1/videos/{video_id}) returns the full video object:
| Field | Type | Description |
|---|---|---|
id |
string | Opaque encoded video ID — pass as-is to the status / download endpoints. |
object |
string | Always video. |
status |
string | processing, completed, or failed. |
seconds |
integer | Duration of the generated video. |
resolution |
string | Output resolution, lowercase <height>p (e.g. 720p). |
ratio |
string | Output aspect ratio (e.g. 16:9). |
model |
string | Model used. |
output_url |
string | Download URL (present when status = completed, for models that return one — not Veo). |
error |
object | { "code": "...", "message": "..." } (present when status = failed). |
usage |
object | Always present: { "completion_tokens": N, "total_tokens": N } (zeros when the model reports no usage). |
vendor_data |
object | Model-specific fields (e.g. seed, frames, last_frame_url, and any timestamps the model reports). |
Per-model parameter support
All video models share the endpoint above, but accept different parameters. ✅ supported · — not supported.
| Parameter | Veo 3.1 | Seedance 1.x | SIRAYA Seedance 2.0 | SIRAYA Seedance 2.5 | HappyHorse | Kling | Wan 2.7 | Wan 3.0 | Wan Spicy |
|---|---|---|---|---|---|---|---|---|---|
seconds |
✅ | ✅ | ✅ | ✅ (up to 30s) | ✅ (3–15s; not on video editing) | — (uses duration, 3–15s; not on motion control) |
✅ (2–15s) | ✅ (2–30s or -1) |
✅ (2.7: 2–15s; 2.2: 5 or 8) |
aspect_ratio |
✅ | ✅ | ✅ | ✅ | ✅ (text- and reference-to-video only) | ✅ (16:9/9:16/1:1; required on omni without a frame) |
✅ | ✅ (incl. adaptive) |
— |
resolution |
✅ (720p/1080p/4k) | ✅ | ✅ (up to 4k; fast and mini 480p/720p) | ✅ (480p/720p/1080p; no 4k) | ✅ (uppercase 720P/1080P; 480P on 1.1) |
✅ (lowercase 720p/1080p; 4k on 3.0 and 3.0-omni) |
✅ (uppercase 720P/1080P) |
✅ (lowercase; 2k/4k on -pro) |
✅ (lowercase) |
size |
✅ | ✅ | ✅ | ✅ | — | — (refused) | — | — | — |
generate_audio |
✅ | ✅ (1.5 pro Audio only) | ✅ | ✅ (11 languages) | — | — (uses audio) |
✅ | ✅ (defaults to true) |
✅ (2.7 only) |
negative_prompt |
✅ | — | — | — | — | — (refused) | ✅ | — | ✅ (2.7 only) |
seed |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
frame_images (first frame) |
✅ | ✅ | ✅ | ✅ | ✅ | — (use contents → first_frame) |
✅ | — (use first_frame) |
— (use image) |
frame_images (last frame) |
✅ | ✅ | ✅ | ✅ | — | — (use contents → last_frame) |
✅ | — (use last_frame) |
— (use last_image, 2.2 only) |
input_references |
✅ | — | ✅ | ✅ (up to 50 refs, incl. audio-only) | ✅ (1–9 images; source video for editing) | — (use contents: motion control, omni video) |
✅ (incl. driving audio and clip continuation) | — (use reference_*, file, link) |
— |
output_format |
— | — | — | ✅ (mp4/mov) |
— | — (refused) | — | — | — |
extra_body |
✅ | ✅ | ✅ | ✅ | — | — | — | — | — |
HappyHorse and Wan 2.7 keep the shared vocabulary but add top-level fields of their own —
watermarkon both, plusaudio_settingfor video editing, andprompt_extend/audio_urlon Wan 2.7 — and neither has anextra_bodypassthrough. Both choose the capability from the model code (-t2v,-i2v,-r2v, video editing) rather than from the materials you attach. Note the opposite watermark defaults: HappyHorse defaults totrue, Wan 2.7 tofalse. See HappyHorse and Wan for the full parameter sets.Wan 3.0 and Wan Spicy take each material as its own flat, top-level field —
first_frame,last_frame,reference_images,reference_videos,reference_audios,fileandlinkon Wan 3.0;imageandlast_imageon Wan Spicy — instead offrame_images/input_references. They also accept the spellingsdurationandaudio; when both spellings arrive,seconds/generate_audiowin. They are the only video models that support deleting a task. See Wan and Wan Spicy.Kling also keeps the endpoint but has its own vocabulary: it takes
durationandaudio(notseconds/generate_audio), and every material — first/last frame, motion reference, omni-video references — goes in a top-levelcontentsarray instead offrame_images/input_references. The shared spellings it does not use (seconds,generate_audio,size,negative_prompt,output_format,image_url,frame_images,input_references) are refused with a400that names the replacement, not silently ignored. The capability (text-to-video, image-to-video, motion control, omni video) is chosen from the model and the materials you attach. See Kling.
Check our Available Models List for all supported video engines.