# Kling 4.0

Kling 4.0 is Kuaishou's video model announced in September 2026. One model ID covers five modes: text to video, image to video with up to 10 frames, reference-based generation from images, videos and audio, video editing, and video extension. Every clip is 3–30 seconds at 720p or 1080p with stereo sound. Send the request, keep the returned task ID, and read the finished video from the task. Media goes in as URLs.

## Model IDs

| Model ID    | Modes                                | Resolutions     | Length       |
| ----------- | ------------------------------------ | --------------- | ------------ |
| `kling-4-0` | text, image, reference, edit, extend | `720p`, `1080p` | 3–30 seconds |

See the [model page](https://seedrouter.ai/models/kling-4-0#pricing) for current prices.

## Quick example

```bash
curl https://api.seedrouter.ai/v1/videos/generations \
  -H "Authorization: Bearer $SEEDROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kling-4-0",
    "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.",
    "resolution": "720p",
    "duration": 5,
    "aspect_ratio": "16:9"
  }'
```

```python
import os
import requests

response = requests.post(
    "https://api.seedrouter.ai/v1/videos/generations",
    headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
    json={
        "model": "kling-4-0",
        "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.",
        "resolution": "720p",
        "duration": 5,
        "aspect_ratio": "16:9",
    },
    timeout=60,
)
response.raise_for_status()
task_id = response.json()["id"]
```

```javascript
const response = await fetch('https://api.seedrouter.ai/v1/videos/generations', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SEEDROUTER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'kling-4-0',
    prompt: 'A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.',
    resolution: '720p',
    duration: 5,
    aspect_ratio: '16:9',
  }),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const { id: taskId } = await response.json();
```

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    body := strings.NewReader(`{
      "model": "kling-4-0",
      "prompt": "A woman with a red umbrella walks down a neon-lit street on a rainy night, signs shimmering in the puddles, the camera tracking low beside her. No text, no logos.",
      "resolution": "720p",
      "duration": 5,
      "aspect_ratio": "16:9"
    }`)
    req, err := http.NewRequest("POST", "https://api.seedrouter.ai/v1/videos/generations", body)
    if err != nil { panic(err) }
    req.Header.Set("Authorization", "Bearer " + os.Getenv("SEEDROUTER_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 60 * time.Second}
    res, err := client.Do(req)
    if err != nil { panic(err) }
    defer res.Body.Close()
    if res.StatusCode != http.StatusOK { panic(res.Status) }
    var task struct { ID string `json:"id"` }
    if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) }
    fmt.Println(task.ID)
}
```

## Endpoint

```text
POST https://api.seedrouter.ai/v1/videos/generations
```

| Header        | Value                 |
| ------------- | --------------------- |
| Authorization | `Bearer YOUR_API_KEY` |
| Content-Type  | `application/json`    |

The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code.

## Parameters

| Field                      | Type        | Default  | Notes                                                                                                                                                                                          |
| -------------------------- | ----------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`                    | string      | required | `kling-4-0`                                                                                                                                                                                    |
| `prompt`                   | string      | required | Optional for image to video only. Mention references as `@Image1`, `@Video1`, `@Audio1`, numbered from 1 in each list.                                                                         |
| `duration`                 | integer     | `5`      | 3–30 seconds. Edit: left out, the output follows the input video. Extend: the length of the new part.                                                                                          |
| `resolution`               | enum        | `720p`   | `720p` or `1080p`.                                                                                                                                                                             |
| `aspect_ratio`             | enum        | by mode  | `16:9`, `9:16`, `1:1`, `21:9`; `auto` for reference mode only. Defaults: text `16:9`, image the first frame's shape, reference `auto`, edit the input video's shape. Not accepted with extend. |
| `image_urls`               | URL list    | none     | Image to video: up to 2, the first then the last frame. Reference (with `omni_reference_task_type: "reference"`) and edit: up to 10 reference images.                                          |
| `image_with_roles`         | object list | none     | `{"url", "role"}` with role `first_frame`, `last_frame`, `keyframe` (or `middle_frame`) or `reference_image`. Exactly 1 first frame, up to 8 keyframes used in order, 10 frames in total.      |
| `first_frame_image`        | URL         | none     | The first frame for image to video.                                                                                                                                                            |
| `last_frame_image`         | URL         | none     | The last frame for image to video, or the target last frame for extend.                                                                                                                        |
| `video_urls`               | URL list    | none     | Reference videos: up to 5, 30 seconds used in total. For edit or extend, exactly 1 in place of `video_url`.                                                                                    |
| `video_url`                | URL         | none     | The input video for edit or extend; requires `omni_reference_task_type` `edit` or `extend`.                                                                                                    |
| `audio_urls`               | URL list    | none     | Reference audio: up to 3 clips of 5–30 seconds each.                                                                                                                                           |
| `omni_reference_task_type` | enum        | `auto`   | `auto`, `reference`, `edit` or `extend`.                                                                                                                                                       |
| `audio_setting`            | enum        | by mode  | `origin` keeps the input video's audio, `auto` regenerates it. Edit keeps it by default; reference with videos regenerates it by default. Not accepted with extend.                            |

Every clip comes with stereo sound; there is no sound switch. There is no `mode`, `negative_prompt`, `watermark` or multi-shot field. The schema is strict: unknown fields are rejected rather than ignored. `callback_url` is not available; poll the task instead.

## Modes

The mode follows the media you send and `omni_reference_task_type`:

| Mode           | How to select it                                                                                   |
| -------------- | -------------------------------------------------------------------------------------------------- |
| Text to video  | No media.                                                                                          |
| Image to video | A first frame, optionally a last frame and keyframes.                                              |
| Reference      | `video_urls`, `audio_urls` or `reference_image` roles, or `omni_reference_task_type: "reference"`. |
| Edit           | `omni_reference_task_type: "edit"` and one input video.                                            |
| Extend         | `omni_reference_task_type: "extend"` and one input video.                                          |

Frames and reference media cannot be mixed in one request. Next to reference videos or audio, `image_urls` count as reference images only with `omni_reference_task_type: "reference"`; use `reference_image` roles otherwise. A `video_url` without `edit` or `extend` is rejected.

### Keyframes

```json
{
  "model": "kling-4-0",
  "prompt": "A girl walks from the window to the door, then looks back and smiles",
  "image_with_roles": [
    {"url": "https://example.com/1.png", "role": "first_frame"},
    {"url": "https://example.com/2.png", "role": "keyframe"},
    {"url": "https://example.com/3.png", "role": "last_frame"}
  ],
  "duration": 10
}
```

### Reference

```json
{
  "model": "kling-4-0",
  "prompt": "The woman from @Image1 walks along the beach with the camera movement of @Video1",
  "image_with_roles": [{"url": "https://example.com/woman.png", "role": "reference_image"}],
  "video_urls": ["https://example.com/camera.mp4"],
  "aspect_ratio": "auto",
  "duration": 5
}
```

### Edit

```json
{
  "model": "kling-4-0",
  "prompt": "Change the scene to a snowy winter evening",
  "omni_reference_task_type": "edit",
  "video_url": "https://example.com/in.mp4"
}
```

The input video must be at least 3 seconds; only its first 30 seconds are used. Without `duration`, the output follows the input video.

### Extend

```json
{
  "model": "kling-4-0",
  "prompt": "The camera keeps moving forward as the sky grows darker",
  "omni_reference_task_type": "extend",
  "video_url": "https://example.com/in.mp4",
  "duration": 5
}
```

Extension continues from the input video's last frame and returns the original plus the new part. Add `last_frame_image` to choose where it ends.

## Media inputs

Images, videos and audio are public HTTP(S) URLs. Base64 data URIs are not accepted: upload the files to your own storage and pass their URLs. Images, videos and audio together are at most 15 reference files.

## Pricing dimensions

Check the [model pricing section](https://seedrouter.ai/models/kling-4-0#pricing) for current rates. Kling 4.0 is billed per second of video, at a rate set by the resolution:

```text
text, image, reference without videos:  cost = duration × standard rate
extend:                                 cost = new seconds × standard rate
edit, reference with videos:            cost = (output + max(output, input)) × video-input rate
```

`input` is the summed length of the input videos, rounded up to whole seconds and capped at 30. It is measured when the request is accepted, so the amount reserved is the amount charged. A video whose length cannot be read is rejected before anything is charged. Example: editing a 5.2-second video into a 3-second result bills 3 + 6 = 9 seconds. Failed tasks are not charged.

## Output schema

Submission returns the task:

```json
{"id": "task_...", "model": "kling-4-0", "status": "processing", "created_at": 1789689600}
```

### Get the task

```text
GET https://api.seedrouter.ai/v1/tasks/{task_id}
```

Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress.

### Completed task

```json
{
  "id": "task_...",
  "model": "kling-4-0",
  "status": "completed",
  "created_at": 1789689600,
  "finished_at": 1789689800,
  "output": {
    "video_url": "https://static.seedrouter.ai/media/tasks/task_example/0.mp4"
  }
}
```

In our tests 3-second `720p` clips came back as MP4 (H.264) at 1280 × 720 with a stereo AAC track, 2 min 41 s to 4 min 22 s after submission. An extended 5.2-second video came back 8.1 seconds long.

## Errors

Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object.

See the [shared error catalog](https://seedrouter.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance.

```json
{
  "id": "task_...",
  "model": "kling-4-0",
  "status": "failed",
  "error": {
    "code": 60001,
    "message": "The request was rejected by the content policy. Please revise the prompt or input images."
  }
}
```

If submission itself times out, check your tasks before submitting again: the first request may have been accepted.

## Tips

* Describe subject, place, camera move, light and sound; the clip's audio follows the prompt.
* Draft at `720p`, then render the final shot at `1080p` with the same request.
* Give longer clips keyframes so the scene moves where you want it.
* Add `no text, no logos` to keep invented marks out.

## Related

* [Kling 4.0 Playground and pricing](https://seedrouter.ai/models/kling-4-0)
* [Kling 3.0 API reference](https://seedrouter.ai/docs/kling-3-0)
* [Download OpenAPI](https://seedrouter.ai/docs/kling-4-0.openapi.json)
* [Copyable Markdown](https://seedrouter.ai/docs/kling-4-0.md)
