Animate a picture with Kling 3 via API: Python first-frame request
To animate one picture with Kling 3 on Sume, send it as a first_frame in frame_images to POST /v1/videos with model kling-3. Full Python script included.

How do I animate a still image with Kling 3 through Sume?
Post the image URL as a first frame. Set model to kling-3, put the picture in frame_images with frame_type set to first_frame, describe the motion in prompt, and poll the returned job until it is completed.
Kling's blog listed a how-to titled "How to Animate a Picture with AI in Four Steps" on September 30, 2026. This post is the API-side version of the same job: one picture, one motion prompt, one clip.
What does the request need?
Five things matter, and the catalog enforces them. The image must be a public HTTPS URL. The duration must be a whole number from 4 to 15. The aspect ratio must be 16:9, 9:16 or 1:1. The resolution must be 720p or 1080p. Audio is optional through generate_audio.
The picture is the first frame, so it fixes the subject, outfit and framing. The prompt should therefore describe only what moves.
| Field | Value for this job | Rule |
|---|---|---|
| model | kling-3 | Bare catalog id, no provider prefix |
| frame_images | One first_frame entry | Public HTTPS image URL |
| duration | 5 | Whole seconds, 4 to 15 |
| resolution | 720p | 720p or 1080p |
| aspect_ratio | 16:9 | 16:9, 9:16 or 1:1 |
| generate_audio | false | Optional boolean |
What does the Python script look like?
This version uses async HTTP and polls every 30 seconds, the interval the docs suggest. It stops with a message when the key is missing and prints the content URL when the job completes. Download the file with the same bearer token.
import asyncio, os, sys
import httpx
async def main():
key = os.environ.get("SUME_API_KEY")
if not key:
sys.exit("set SUME_API_KEY")
body = {
"model": "kling-3",
"prompt": "The woman turns to the window and smiles, slow push-in",
"frame_images": [{
"type": "image_url",
"image_url": {"url": "https://example.com/photo.png"},
"frame_type": "first_frame",
}],
"duration": 5, "resolution": "720p", "aspect_ratio": "16:9",
"generate_audio": False,
}
headers = {"Authorization": f"Bearer {key}", "Idempotency-Key": "animate-photo-001"}
async with httpx.AsyncClient(headers=headers, timeout=60) as c:
r = await c.post("https://api.sume.com/v1/videos", json=body)
r.raise_for_status()
poll = r.json()["polling_url"]
while True:
await asyncio.sleep(30)
s = (await c.get(poll)).json()
if s["status"] in ("completed", "failed", "canceled"):
break
print(s["status"], s.get("unsigned_urls") or s.get("error"))
asyncio.run(main())What goes wrong most often?
A picture that is not publicly reachable is the usual cause of a failed job, and the docs say reference images must be accessible over public HTTPS. A second cause is sending the picture as input_references: kling-3 takes no references, so that field returns a 400 unsupported_capability, covered in the input_references fix.
A third cause is a mismatched aspect ratio. If the picture is portrait and you ask for 16:9, say so in your plan; pick 9:16 for portrait pictures, since kling-3 offers 16:9, 9:16 and 1:1 only.
When is Kling 3 the wrong tool for this?
If you want to move a person by copying motion from another video, that is a different product, motion control. If you need a clip longer than 15 seconds from one picture, use seedance-2.5, which accepts 4 to 30 seconds. Sume makes no promise about how faithfully any model keeps the picture's details over the full clip, so look at the last frame before you ship it. The reserve on submit is the provider list price times 1.25, and usage.cost on the finished job is the Sume billable amount.
Sources
Related posts
More in Developers
- Are Claude Code mods safe with a Sume API key in your env?
Claude Code mods run unsandboxed and can read env vars and settings files. What that means for a Sume API key, the CLI config file and an OAuth session.
- attachment_too_large 413: 30 MB per image, 500 MB per run
A Format run 413 attachment_too_large means one image is over 30 MB or the set is over 500 MB. It is a different 413 from payload_too_large (4 MiB body).
- Try Avatar 1.0 in the Sume playground before you write any code
Use the Sume Avatar playground to validate an avatar or avatar video payload, then move the same body into curl, the CLI or an agent without a rewrite.
- Bulk run: a bad item fails the whole create, a child failure does not
In a Sume bulk Format run, a bad item is a 400 with details.index and no queue; a child that fails admission after the 202 becomes one failed item.
Written by Sume