Image to Video
Generate a video from a first frame, with optional keyframes and a last frame (Kling 4.0 image_to_video).
Kling 4.0 starts the video from your image, and can also pass through keyframes and end on a last frame, generating what happens in between.
Create a task
https://api.nanoapi.ai/v1/tasksUse the shared create endpoint with model: "kling-4.0". It usually responds in under 1 second and the cost is frozen within a few seconds; the video usually takes 1–5 minutes. Get the result once the task has finished.
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <API key>, see Authentication. |
Content-Type | Yes | application/json |
Idempotency-Key | No | A unique string for every new task, ideally a UUID (1–255 characters). See Preventing duplicate tasks. |
Body
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | kling-4.0. |
mode | string | Yes | image_to_video. |
image_urls | string[] | Yes | 1–10 images, used in order: the first is the first frame; with 2 or more, the last one is the last frame and those in between are keyframes. A single image is the first frame (you can't give only a last frame). Each is an http(s) link of at most 4096 characters that can be downloaded directly, not a private address. |
prompt | string | No | How the scene should change, at most 8000 characters. Refer to the images as @Image1 and so on, see Referring to files. |
aspect_ratio | string | Yes | auto, 21:9, 16:9, 9:16 or 1:1. auto follows the first frame. |
resolution | string | Yes | 720p or 1080p. Sets the price. |
duration | integer | Yes | Output length in seconds, 3–30. It's what you pay for, see Pricing. |
webhook_url | string | No | Notified when the task succeeds or fails: https, up to 2048 characters, not a private, loopback or reserved address. See Webhooks. |
video_url and video_urls aren't accepted: sending either returns 400 invalid_request with param set to it.
A first frame, a keyframe and a last frame, 720p, 5 seconds:
curl https://api.nanoapi.ai/v1/tasks \
-H "Authorization: Bearer $NANOAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-4.0",
"mode": "image_to_video",
"image_urls": [
"https://example.com/start.jpg",
"https://example.com/middle.jpg",
"https://example.com/end.jpg"
],
"prompt": "A slow camera flight from the mountains down to the lake",
"aspect_ratio": "auto",
"resolution": "720p",
"duration": 5
}'Response: 200 OK. data is the newly created task, with only these fields; each one is described in Create a task: Response. Keep data.id to get the result: once the task succeeds, the video is at data.outputs[0].url of the retrieved task or the webhook. The task can still fail after it's created (for example a file can't be downloaded), so go by what retrieving the task or the webhook tells you.
{
"code": 200,
"message": "success",
"data": {
"object": "task",
"id": "tk_01jbc4k7m2n9p5q8r3s6t1v4w7",
"model": "kling-4.0",
"status": "queued",
"error": null,
"created_at": "2026-10-30T08:30:00Z"
}
}Pricing
cost = duration × price per second of the resolutionLoading the current prices…
Example: 720p for 5 seconds (the request above) costs 5 × the 720p price per second.
Billed seconds are the duration you ask for, however many images you send. Prices change, so read the current ones from GET /v1/products (the prices rows whose mode is this mode) instead of hard-coding them; billing.frozen on the retrieved task is what counts. All Kling 4.0 prices: Kling 4.0 → Pricing.
Errors
Create request errors: the request fails with an HTTP error and no task is created. Specific to this mode:
| Status | error.type | When | What to do |
|---|---|---|---|
400 | invalid_request | image_urls is missing or doesn't have 1–10 images, video_url or video_urls was sent, or aspect_ratio, resolution or duration is missing or isn't one of the values above. param names the parameter. | Fix the parameter param names and send the request again. |
Other errors of the create endpoint (401, 402, 429 and so on): Create a task → Errors.
Task failures: the create request succeeded (200) and the task later turned failed. There's no HTTP status: the reason is the task's error.type, from retrieving the task or the webhook.
error.type | When | What to do |
|---|---|---|
invalid_media | An image can't be downloaded or read (corrupt or an unsupported format). Found when the files are downloaded, a few seconds after the task is submitted. The frozen amount is returned in full. | Use publicly downloadable image links and create the task again. |
Failure reasons shared by every mode (such as a balance too low for the task): Kling 4.0 → Errors; all of them: Failure reasons.