Skip to content
Get Started

Video

This quickstart walks you through generating your first video with SIRAYA Model Router.

Video generation

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"
  }'

  • https://llm.siraya.ai/v1/videos/generations is the base URL
  • <API_KEY> is your API Key generated in API page.
  • model is the model name, such as veo-3.1-generate-001, available model list can be access in Model page.
  • prompt is the prompt.
  • async (boolean, optional, default false) — when false, the request waits for generation to finish and returns the finished video url. When true, the request returns immediately with a video id you poll for status (recommended for longer videos, to avoid request timeouts).
  • callbackUrl (string, optional) — only used when async is true; must be an http(s) URL. The full URL the router will POST to once generation completes (or fails), so you don't have to poll.

Example response

{
  "created":1779869107,
  "data":[
    {
      "url":"https://resources.siraya.ai/v1/videos/video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31ITzZT46hwKyO76u6tQqyIG2pJpuH2fwVp8xDMHUsL-Xcb6Z23Zwsx3CyCodxCuEhffwrnlVa2FW__anjjNthFJJHGTSoTvTX3x-so9lSXeqaKTSjgoNgcEpEAzsJqUXN-TCavtB4MBY9F3spP3qKZa354Bw4ntid5PnuvoPGDe_A9OWwAXe_k8mshQhrVp52KSlleDAOAHdqG-k44_6kROl0Q11IsneT_Qq6SU5Bw/content"
    }
  ],
  "error":{}
}     

Asynchronous generation

Video generation can take a while. Set async: true to return immediately with a video id instead of waiting — then either poll for status or receive a callback.

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",
    "async": true,
    "callbackUrl": "https://your-app.com/webhooks/siraya-video"
  }'

Example response — the job is accepted; status is processing and no url yet:

{
  "id": "video_n6Sn-1aIT3z8x-QF3xxD0wiUTjl6s31...",
  "object": "video",
  "status": "processing",
  "model": "veo-3.1-generate-001",
  "seconds": 8,
  "usage": { "completion_tokens": 0, "total_tokens": 0 }
}

Keep the returned id — you use it to poll status and download the result.

1. Poll the status

Call the status endpoint with the id until status is completed (or failed):

curl https://llm.siraya.ai/v1/videos/<video_id> \
    -H "Authorization: Bearer <API_KEY>"
{
  "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 }
}
  • status is one of processing, completed, or failed.
  • output_url is returned by some models only (not by Veo); when it is absent, download from the /content endpoint below.
  • When failed, an error object ({"code": "...", "message": "..."}) is included instead of output_url.
  • Poll every few seconds; back off on 429.

2. Download the video

Once status is completed, download the raw video bytes (Content-Type: video/mp4):

curl https://llm.siraya.ai/v1/videos/<video_id>/content \
    -H "Authorization: Bearer <API_KEY>" \
    -o output.mp4

When the status call returns an output_url, you can fetch that directly instead.

Callback (instead of polling)

If you passed 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 (not finished within about 16 minutes). On failed and timeout, data is empty and error.message carries the reason. The id is also 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.

In synchronous mode (no async), a failed or timed-out job returns HTTP 400 with {"created": ..., "data": {}, "error": {"message": "..."}}.