Seedance image-to-video: animating a still over API
Updated 2026-10-02
Image-to-video is the most reliable way to control composition: you fix the first frame and let the model decide only the motion. With Seedance through VideoRouter, it is the same POST /videos request as text-to-video plus one field.
The minimal request
import requests, time
H = {"Authorization": "Bearer llmr_sk_live_...", "Content-Type": "application/json"}
job = requests.post("https://videorouter.sh/api/v1/videos", headers=H, json={
"model": "bytedance/seedance-2.0-mini",
"prompt": "slow push-in, the steam rises from the cup, soft window light",
"start_image_url": "https://example.com/cup.jpg",
"duration_secs": 5,
"aspect_ratio": "16:9",
"resolution": "720p",
}).json()
while True:
j = requests.get(f"https://videorouter.sh/api/v1/videos/{job['id']}", headers=H).json()
if j["status"] in ("completed", "failed"):
break
time.sleep(5)
start_image_url accepts a public https:// URL or an inline data:image/...;base64,... URI. On most Seedance rows the model id is the same one you use for text-to-video: omit the field and you get text-to-video, include it and the model animates that frame. Jobs run queued to in_progress to completed or failed, and polling is free.
Prompting for motion, not for the image
The image already carries subject, style and lighting. A prompt that re-describes it wastes tokens and can fight the pixels. Spend the prompt on what changes:
- Camera: "slow dolly in", "static locked-off shot", "orbit left". Name one camera move per clip; stacked moves tend to muddy.
- Subject action: one verb phrase, specific. "Turns her head toward the window" is better than "moves naturally".
- Environment motion: steam, hair, fabric, water, leaves. Secondary motion makes a still read as footage.
- Negative space: say what must stay fixed ("logo stays sharp and unchanged") when the image contains text or a product mark.
Short clips behave better than long ones for the same reason: fewer frames to drift away from the start image. If you need a long sequence, chain shots, and feed each shot's last frame (extract it yourself) in as the next start_image_url.
Aspect ratio and resolution
aspect_ratio takes values such as 16:9, 9:16, 1:1, 4:3, 3:4 and 21:9; resolution is a tier the specific model supports. Two rules matter in practice:
- Match the source image's shape. If you request 9:16 from a landscape photo, expect cropping or reframing you did not plan for. Crop the image to the target ratio first.
- An unsupported ratio/resolution pair is silently ignored (the model default is used) rather than returning a 400. Read the returned job to see what you got, and check the model page for the tiers it actually offers.
Seedance is priced per second per resolution tier, so the tier you request changes the bill. Don't render 1080p for a layout check.
Draft on a cheaper variant, then finalise
Seedance ships as separate model ids: bytedance/seedance-2.0-mini, bytedance/seedance-2.0-fast, bytedance/seedance-2.0 and bytedance/seedance-2.5. Only the string changes, so a two-stage pipeline is a loop:
- Run every candidate image and motion prompt on a low-cost variant at a low resolution tier and short duration.
- Review, pick winners, discard the rest.
- Re-submit only the winners to a full model with the same
start_image_urland a higher tier.
Variants are different models, so an approved draft will not be pixel-identical when re-rendered; treat the draft as a check on composition and motion intent, not on final texture. The variant guide covers when each earns its place.
Choosing a target for the first frame
Before you submit, decide whether the first frame needs to match the image exactly. For product shots and logos it usually does, so keep the clip short, ask for a gentle camera move, and avoid prompts that invite the subject to turn away. For atmospheric shots, such as landscapes, interiors and portraits, you can ask for more motion because slight drift from the source is acceptable. Testing both styles on a cheap variant takes a few cents of requests and saves a full-price retry later.
Pitfalls
- Do not combine fields.
start_image_urlis image-to-video; passing it together withinput_video_url(editing) is rejected. For multiple reference images, use the reference-to-video arrays instead. - Image URLs must be reachable from the host. Expired presigned links are the most common cause of a failed image-to-video job. Use
data:URIs for small images if hosting is awkward. - Duration is snapped to the nearest value the model supports, and some models bill a fixed length. Billing is at creation from the snapped duration, so retries multiply cost; check the response before re-submitting.
- Pinning vs floating. Unpinned requests go to the cheapest healthy host and fail over on outages; pin with a suffix such as
bytedance/seedance-2.0-mini/<host>only when you need a specific host's behaviour.
Batching many images
If you animate a catalogue of product photos, submit jobs concurrently but cap concurrency yourself, store each job id with the source image URL before polling, and treat failed as terminal for that job. Re-submit only after reading the error: a bad image URL will fail every time, while an upstream timeout is worth one retry. Keep the prompt template identical across the batch so differences in output come from the images, not the wording.
See what hosts cost
The same Seedance variant is sold by many providers at different per-second rates. The live table shows the cheapest and priciest host per row:
| Model | Cheapest host | Priciest host | Cheapest is | Hosts |
|---|---|---|---|---|
| bytedance/seedance-2.5 (480p) | OpenSand $0.0525 / second | Fal-US $0.2646 / second | 80% lower | 9 |
| bytedance/seedance-2.0 (2160p) | MachGen $0.59 / second | Fal $1.5552 / second | 62% lower | 9 |
| bytedance/seedance-2.0-fast (480p) | Atlas Cloud $0.027 / second | Fal $0.2419 / second | 89% lower | 9 |
| bytedance/seedance-2.0-mini (480p) | OpenSand $0.0104 / second | Fal $0.0721 / second | 86% lower | 8 |
| seedance-2-mini-unrestricted (480p) | OpenSand $0.0114 / second | SandBase $0.0721 / second | 84% lower | 3 |
| seedance-2-5-unrestricted (1080p) | OpenSand $0.3482 / second | TOAPIS $0.5881 / second | 41% lower | 2 |
| seedance-2.0-fast-unrestricted (480p) | OpenSand $0.0344 / second | SandBase $0.0448 / second | 23% lower | 2 |
| seedance-2-unrestricted (2160p) | OpenSand $0.661 / second | TOAPIS $0.7966 / second | 17% lower | 2 |
Per second, before VideoRouter's 2% platform fee. For tiered models each row compares the resolution tier with the widest host-to-host gap. Built 2026-10-02 from the live catalog.
Get an API key and run the snippet above, or see the quickstart and the model list.
Frequently asked questions
How do I animate an image with the Seedance API?
Send POST /videos with a Seedance model id, a motion prompt and start_image_url set to a public URL or a base64 data URI, then poll the job until it completes.
Should the prompt describe the image?
Mostly no. The start image already defines subject and style, so describe the camera move, the subject action and any environmental motion instead.
What happens if my aspect ratio or resolution is not supported?
The unsupported combination is ignored and the model default is used, not rejected. Check the returned job and the model page for the tiers that model offers.
Can I render a draft cheaply and then redo it at higher quality?
Yes. Variants are separate model ids, so you can test on Mini or Fast and re-submit the same image and prompt to 2.0 or 2.5. Expect the final to differ in detail from the draft.
Keep reading
- Seedance 2.5 vs 2.0 vs Fast vs Mini — Choosing a Variant for API Use
- Seedance Reference-to-Video API: Images, Video, Audio Refs
- Seedance vs Kling vs Veo API: How to Choose by Workload
- How to Call the Seedance 2.5 API: curl and Python Examples
VideoRouter puts it next to dozens of other video and image models behind one API key, so you can compare providers, prices and fail over automatically. Compare providers on VideoRouter →