Skip to content

Video generation ​

primerouter offers Seedance video generation: text-to-video, first/last-frame video, and video driven by reference images, reference videos or reference audio. Tasks are asynchronous: submit to get a task ID, poll for progress, and download the video once it completes.

You need a key in the "Seedance" group

Video models are only in the Seedance group. Create (or edit) an API key in the console, set its group to "Seedance", and use it for the endpoints below.

EndpointPurpose
POST /v1/video/generationsSubmit a task
POST /v1/videosSubmit a task (same as above, OpenAI video path)
GET /v1/video/generations/{task_id}Query a task (generic format)
GET /v1/videos/{task_id}Query a task (OpenAI video format)

The two submit endpoints are equivalent; both take a JSON body.

Models ​

ModelLengthResolutions
seedance-2.04–15 s480P 720P 1080P 2K 4K
seedance-2.54–30 s480P 720P 1080P 2K 4K

Text to video ​

bash
curl https://primerouter.ai/v1/video/generations \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.0",
    "prompt": "A red paper boat drifts across a calm lake at sunrise, slow push-in",
    "duration": 5,
    "metadata": { "resolution": "1080P", "ratio": "16:9" }
  }'

Response:

json
{
  "id": "task_xxxxxxxx",
  "task_id": "task_xxxxxxxx",
  "object": "video",
  "model": "seedance-2.0",
  "status": "queued",
  "progress": 0,
  "created_at": 1761484800
}

Keep the id to query the task.

First and last frame ​

The first entry of images is the first frame, the second the last frame (one entry gives a first frame only; image takes a single URL too):

bash
curl https://primerouter.ai/v1/video/generations \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5",
    "prompt": "The bud slowly opens into a full bloom",
    "images": ["https://example.com/first.png", "https://example.com/last.png"],
    "duration": 8,
    "metadata": { "resolution": "720P" }
  }'

Reference images, videos and audio ​

Put reference media in the metadata.content array, each item with its type and role:

bash
curl https://primerouter.ai/v1/video/generations \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.0",
    "prompt": "Follow the camera move of the reference video and walk the character in",
    "duration": 6,
    "metadata": {
      "resolution": "720P",
      "content": [
        { "type": "image_url", "image_url": { "url": "https://example.com/character.png" }, "role": "reference_image" },
        { "type": "video_url", "video_url": { "url": "https://example.com/camera-move.mp4" }, "role": "reference_video" }
      ]
    }
  }'
  • type must be image_url, video_url or audio_url (text items are ignored; put text in prompt)
  • role is reference_image, reference_video or reference_audio
  • Reference audio cannot be used alone: add a reference image or reference video, or the task fails
  • Reference videos may total at most 15 seconds

Query a task ​

bash
curl https://primerouter.ai/v1/videos/task_xxxxxxxx \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY"

status goes queued → in_progress → completed or failed. Right after submitting, before progress is synced, status may be unknown: treat it as in progress and keep polling. When completed, the video link is in metadata.url:

json
{
  "id": "task_xxxxxxxx",
  "object": "video",
  "model": "seedance-2.0",
  "status": "completed",
  "progress": 100,
  "metadata": { "url": "https://...mp4?..." }
}

On failure, error.message gives the reason.

With the generic format GET /v1/video/generations/{task_id}, the status is in data.status (QUEUED / IN_PROGRESS / SUCCESS / FAILURE; right after submitting it may be NOT_START, which also means in progress), the video link in data.result_url and the failure reason in data.fail_reason.

Most tasks finish in 2–5 minutes; polling every 15–30 seconds is enough.

Download within 12 hours

The download link is temporary. Download and keep the video within 12 hours; it cannot be fetched again after that.

Request parameters ​

FieldDescription
modelseedance-2.0 or seedance-2.5, required
promptPrompt, required
durationLength in seconds (integer). Defaults to 5; -1 lets the model choose the length
secondsAnother way to give the length (string, e.g. "8"); duration wins
image / imagesFirst / last frame image URLs, at most 2
metadata.resolution480P 720P 1080P 2K 4K, upper case; defaults to 720P
metadata.ratio21:9 16:9 4:3 1:1 3:4 9:16 adaptive
metadata.durationA third way to give the length (integer); used only when neither duration nor seconds is set
metadata.contentReference images / videos / audio, see above
metadata.optionsOnly return_last_frame is accepted (the last frame image is not returned in the result yet; passing it does not affect generation)

Notes:

  • Resolution and length come from these parameters only; writing them in the prompt (e.g. --rs 1080p --dur 10) has no effect
  • Media URLs must be publicly reachable http / https links. If a link cannot be opened, the task fails (not charged)
  • Images with real human faces may be rejected and the task fails (not charged)
  • Other metadata fields (such as seed or watermark) have no effect
  • Form uploads (multipart/form-data) and input_reference are not supported; host the media and pass its URL

Errors ​

These errors come back on submit as HTTP 400 and are not charged:

Error messageCause
only JSON requests with media URLs are supportedA form upload, or input_reference was set
images accepts at most 2 entries (first and last frame); put reference images in metadata.contentMore than 2 images; put reference images in metadata.content
metadata.options only supports return_last_framemetadata.options has another field
metadata.content items must be image_url, video_url, audio_url or textmetadata.content has an unsupported type
media URLs must use http or httpsA media link is not http / https
model <name> is not available for video generationThe model cannot be used for video generation; use a model from the table above or contact the administrator
model <name> has no price configured, please contact the administratorThe model has no price yet; contact the administrator

A resolution, ratio or length outside the supported values (e.g. lower-case 1080p, or 20 seconds on seedance-2.0) is also rejected on submit with a 400 and not charged.

Billing ​

  • Billed per second: the price depends on the model and output resolution, times the video length
  • With a reference video, its seconds are billed too (at the "with reference video" rate of the same resolution; input and output each billed)
  • Failed generations are not charged
  • On submit, the most the request could cost is held (e.g. duration: -1 holds the model's longest length); once the video is done, the difference is refunded or charged to match actual usage
  • Per-second prices for each resolution are on the pricing page, "Seedance" tab, group ratio included

Built for transparent, auditable, crypto-native AI inference. About · Terms · Privacy