Animating a still with the Kling image-to-video API
Updated 2026-10-02
Image-to-video with Kling is the same POST /videos call you use for text-to-video, plus one field: start_image_url. The image becomes the first frame, and the prompt describes what should happen next. That sounds trivial, and the request is, but most wasted generations come from what you put in the prompt and the image, not from the API call. This guide covers the request, how to write motion prompts, how to pick a tier, and the mistakes worth avoiding.
The request
Base URL is https://videorouter.sh/api/v1. The job is asynchronous: you get an id back with status queued, then poll GET /videos/{id} until it reads completed or failed. Polling is free.
import time, requests
H = {"Authorization": "Bearer llmr_sk_live_...", "Content-Type": "application/json"}
BASE = "https://videorouter.sh/api/v1"
job = requests.post(f"{BASE}/videos", headers=H, json={
"model": "kling-v3.0-std",
"start_image_url": "https://example.com/product-shot.jpg",
"prompt": "slow dolly-in, steam rises from the cup, soft window light flickers",
"duration_secs": 5,
"aspect_ratio": "16:9",
}).json()
while job["status"] not in ("completed", "failed"):
time.sleep(5)
job = requests.get(f"{BASE}/videos/{job['id']}", headers=H).json()
print(job["data"][0]["url"] if job["status"] == "completed" else job["error"])
start_image_url accepts either a public https:// URL or an inline data:image/...;base64,... URI. If the file only exists locally and base64 would make the request unwieldy, the API reference describes a POST /v1/uploads endpoint that stages a file and returns a URL you can pass back in.
Fields that matter for image-to-video
| Field | Notes |
|---|---|
model | One of kling-v3.0-std, kling-v3.0-pro, kling-v3.0-4k. Tiers are separate model ids, not a quality flag. |
start_image_url | The first frame. Public URL or data URI. |
prompt | Motion and camera description. Do not re-describe the image. |
duration_secs | Billed once at creation by the duration you request, so do not ask for more than you will use. |
aspect_ratio, resolution | Optional. The API reference says an unsupported combination is silently ignored and the model default is used rather than returning a 400, so check the output dimensions, not just the status code. |
Two constraints from the API reference are easy to trip over. First, a model accepts either a start image or a set of reference files in one call, not both (the one documented exception is Motion Control, covered in a separate guide). Second, end_image_url is currently documented as rejected with a 400 on every model, so do not build a first-frame-plus-last-frame flow on it without checking the model page first.
Writing a motion prompt
The image already carries the subject, composition, lighting and style. The prompt only needs to add change over time. A structure that works well in practice:
- Camera move: static, slow push-in, pan left, orbit. One move per clip.
- Subject motion: what moves, and how fast. "Hair lifts slightly in a light breeze" beats "dynamic motion".
- Environment motion: background elements that should stay alive (steam, leaves, traffic).
- What must not change: logos, text on packaging, faces. Say it plainly.
Avoid re-describing what is visible ("a woman in a red coat standing on a street") because it adds nothing and can pull the model toward a different interpretation than your frame. Avoid stacking three camera moves in five seconds; the result tends to look like a mistake rather than a style.
Choosing a tier
Image-to-video is the case where tiering pays off most, because the image fixes the look and you are mostly testing motion. A sensible loop is to iterate prompts on kling-v3.0-std, then resubmit the approved prompt and image on kling-v3.0-pro or kling-v3.0-4k for the deliverable. The swap is one string. See the Std vs Pro vs 4K guide for the workflow and the live price table for current per-second rates.
If you want a particular host, suffix the model id, for example kling-v3.0-std/novita. Without a suffix, requests route to the cheaper healthy host. Pin only when you have a reason, such as keeping output consistent across a batch.
Pitfalls
- Low-resolution or heavily compressed inputs. The model animates what you give it, artifacts included. Start from the cleanest source you have.
- Mismatched aspect ratio. If your image is portrait and you request
16:9, expect cropping or reframing. Match the ratio to the source, or generate the image at the target ratio first. - Private or expiring URLs. The host has to fetch the image. Signed URLs that expire in a minute, or links behind a login, fail in ways that look like model errors. Use a stable public URL or a data URI.
- Re-submitting a slow job. Polling is free; a second job is a second charge. Wait for the first to finish.
- Treating
failedas billed. Jobs that fail upstream are not billed, so retrying a failed job is safe. A completed job you dislike is billed.
Handling errors
Errors use the OpenAI-style envelope {"error": {"message", "type", "code"} }. A bad image URL or a missing required field comes back as a 400 invalid_request_error at creation time; a failure after queuing shows up as status: "failed" on the job. Handle both paths.
For a runnable first request with your own key, see the quickstart, or create an account and try the snippet above.
Frequently asked questions
Which field animates a still image with Kling?
Pass start_image_url alongside prompt on POST /videos. It takes a public https URL or a base64 data URI, and the image becomes the first frame.
Can I send a last frame as well?
The API reference currently states end_image_url is rejected with a 400 on every model. Check the model page before designing around first-and-last-frame control.
Do I need a different model id for image-to-video?
No. The same Kling model ids (for example kling-v3.0-std) handle text-to-video and image-to-video; adding start_image_url switches the mode.
Am I billed if the job fails?
Jobs that fail upstream are not billed. Billing happens once at creation by the duration you requested, and polling the job is free.
Keep reading
- Kling v3.0 Std vs Pro vs 4K — Which Tier Should You Use?
- Kling Motion Control API: Reference Video + Character Image
- Kling O3 (Omni) vs Kling v3: Which Model Should You Call?
- How to Call the Kling API With curl: Step by Step
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 →