# Kling 4.0 (video) > Kling 4.0 makes video from text, from one first frame, or from reference media. It renders at 720p or 1080p, in any whole length from 3 to 30 seconds. It is the Kling model for new video: it keeps a person or a product the same from shot to shot. Status: roasOS API v1.1. Catalog `model-catalog@2026-10-06.v5`, pricing `customer-pricing@2026-11-05.v15`. The endpoint `POST /v1/video/kling-4` is live. `POST /v1/generations` stays for one minor version as a deprecated alias (see "Today"). ## Endpoint POST https://api.roasos.com/v1/video/kling-4 Auth: Authorization: Bearer roasos_sk_… (scope api:write). Idempotency-Key required. quote_only / quote_id / webhook_url as in https://docs.roasos.com/llms.txt. ## Good at Kling 4.0 is the only Kling video model since 2026-10-29. It replaced Kling 3, Kling 3 Pro, Kling O3, Kling O3 Pro and both 4K tiers, and those endpoints are removed. Use it to keep one or more people, or a product, the same across a clip. Send each person or product as an element: one frontal image and up to 3 more views. The prompt names each element once as `@Element1`, `@Element2`, and so on. Send `avatar_id` to attach a saved person as an element. An element can also be a video of the person or object (`video_url`, 3 to 8 seconds, at least 700 px on each side) instead of images. Up to 3 elements can be video elements, and their seconds count in the 30-second clip total and in the price. Up to 3 elements can carry a `voice_id`: a Kling voice that you made with fal's create-voice endpoint. The element then speaks in that voice. To change an existing video, use [Kling 4.0 Edit](/models/video-edit/kling-4). The reference lane takes up to 10 images (`references`, named `@Image1..N`), 5 video clips (`video_urls`, named `@Video1..N`) and 7 elements. A first frame (`image_url`) on the reference lane is the literal opening frame, and it counts as one of the 10 images. Each reference clip must be 3 to 30 seconds long, and all clips together must be 30 seconds or less. A reference clip shows motion or style to follow. It does not edit that clip. Use `multi_prompt` for a board of shots in one generation: up to 8 shots, each with its own prompt (512 characters or less) and its own length. The shot lengths must add up to `duration_seconds`. Text-to-video takes 9:16, 16:9, 1:1 and 21:9. The reference lane also takes `auto`, which follows the references. Image-to-video takes its framing from the first frame, and `end_image_url` sets the last frame. The provider documents no audio switch. The endpoint does not accept `generate_audio`. ## Pricing Unit: clip. Pricing key: `kling-4`. | request | credits | |---|---| | `3s_1080p` | 9 | | `17s_1080p` | 48 | | `30s_1080p` | 85 | Credits come from the roasOS pricing table (`MODEL_COSTS`) through the catalog. No other field changes the price. ## Modes - `text-to-video` - `image-to-video` - `reference-to-video` The worker derives the mode from the media fields of the request. Provider endpoints: `kling/v4/image-to-video` · `kling/v4/reference-to-video` · `kling/v4/text-to-video`. ## Request fields | field | type | required | default | rule | |---|---|---|---|---| | `aspect_ratio` | enum | no | `16:9` | `9:16`, `16:9`, `1:1`, `21:9`, `auto`; only in `text-to-video`, `reference-to-video` | | `avatar_id` | string | no | — | UUID; only in `reference-to-video` | | `avatar_outfit` | string | no | — | ≤ 500 characters | | `duration_seconds` | integer enum | no | `5` | `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`, `13`, `14`, `15`, `16`, `17`, `18`, `19`, `20`, `21`, `22`, `23`, `24`, `25`, `26`, `27`, `28`, `29`, `30` | | `elements` | object[] | no | — | 1–7 items; each `{ frontal_image_url, reference_image_urls, video_url, voice_id }`; only in `reference-to-video` | | `end_image_url` | string | no | — | https URL; ≤ 4,096 characters; only in `image-to-video` | | `extend_of_generation_id` | string | no | — | UUID | | `image_url` | string | no | — | https URL; ≤ 4,096 characters; only in `image-to-video` | | `mode` | enum | no | — | `text-to-video`, `image-to-video`, `reference-to-video` | | `multi_prompt` | object[] | no | — | 1–8 items; each `{ prompt, duration_seconds }` | | `prompt` | string | no | — | ≥ 1 character; ≤ 2,500 characters | | `quote_id` | string | no | — | UUID | | `quote_only` | boolean | no | `false` | — | | `references` | string[] | no | — | ≤ 10 items; only in `reference-to-video` | | `resolution` | enum | no | `1080p` | `720p`, `1080p` | | `scene_id` | string | no | — | UUID | | `video_urls` | string[] | no | — | 1–5 items; only in `reference-to-video` | | `wait_timeout_seconds` | integer | no | `0` | 0–60 | | `webhook_url` | string | no | — | https URL; ≤ 4,096 characters | The schema is strict: a field that is not in this table returns `400 unsupported_option`. Field names are the roasOS role names, one name per role across every family. ## Media - `avatar_id` — identity; the saved character reference sheet, with a derived portrait only where the model requires a single face or source frame - `elements` — identity; one frontal image plus more views, per person or object - `references` — style and appearance references - `image_url` — first frame (or the single source image) - `end_image_url` — last frame - `scene_id` — first frame — a scene this workspace owns - `video_urls` — reference videos | role | items | max size | content types | duration | |---|---|---|---|---| | `end_image_url` | ≤ 1 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | | `image_url` | ≤ 1 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | | `references` | ≤ 10 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | | `video_urls` | ≤ 5 | 100 MB | `video/mp4` | 3–30 s | - Refused: `product_id`, `product_images`, `reference_images`, `scene_image`, `video_url`, `audio_urls`, `audio_url`, `voice_id`. A refused role returns `400 unsupported_option`. - Every URL must be an immutable object on `https://cdn.roasos.com/…` that your workspace owns; any other URL is `400 reference_media_not_workspace_owned`. Upload with `POST /v1/uploads` (direct POST of the bytes to `put_url`, or a `source_url` import), then use the returned CDN URL. ## Prompt Limit 2,500 characters for `prompt`, and 512 characters for each `multi_prompt` shot. - Think in shots: "Shot 1 (3s): …". Define each subject and the setting in shot 1, and keep them the same. - In each shot, write the subject, the action and its motion path, the setting, the camera, and the mood. Use one action and one camera move for each shot. - Write motion as physics: the main movement, then the movement of hair, fabric or particles. - Write each spoken line in quotes with a speaker label and a voice: [Mia, warm]: "Okay, this texture." - In image-to-video, write only what changes. The first frame sets the scene. - Use each `@Image`, `@Video` and `@Element` tag once. The platform adds a missing `@Image` or `@Video` tag at the end of a single prompt. You must write each `@Element` tag yourself. - End with "No text overlays, no captions." Add text in post-production. ## Not exposed - `video_urls`: values not exposed — `MOV containers`. - `middle_image_urls`: not accepted by this public endpoint. - `voice_ids`: not accepted by this public endpoint. ## Result Result kind `video`. Always present: `url`. ```json { "data": { "id": "gen_…", "kind": "video", "model": "kling-4", "status": "completed", "result": {"url":"https://cdn.roasos.com/workspaces/ws_01/result"} } } ``` Files live on `https://cdn.roasos.com` and are immutable; a result URL can be a media input to the next call. Poll `GET /v1/jobs/{id}/status` → `{ id, status, updated_at }`, then `GET /v1/jobs/{id}/result` (`409 run_not_completed` until the job is `completed`, `failed` or `canceled`). Statuses: `queued → processing → completed | failed | canceled`. ## Example ```bash # 1. quote — nothing is spent curl -X POST https://api.roasos.com/v1/video/kling-4 \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-kling-4-0001" \ -H "Content-Type: application/json" \ -d '{"quote_only":true,"prompt":"A woman holds the bottle at eye level in a bright kitchen, morning light, static camera."}' # → 200 { "data": { "kind": "quote", "quote_id": "q_7Hk…", "credits": 9, "expires_at": "…", "confirmation": { "model": "kling-4", "example": "3s_1080p" } } } # 2. run — the same body and the same Idempotency-Key, quote_id instead of quote_only curl -X POST https://api.roasos.com/v1/video/kling-4 \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-kling-4-0001" \ -H "Content-Type: application/json" \ -d '{"quote_id":"q_7Hk…","prompt":"A woman holds the bottle at eye level in a bright kitchen, morning light, static camera."}' # → 201 { "data": { "id": "gen_…", "kind": "video", "model": "kling-4", "status": "queued", "credits_reserved": 9, "links": { "status": "/v1/jobs/gen_…/status", "result": "/v1/jobs/gen_…/result" } } } # 3. poll curl https://api.roasos.com/v1/jobs/gen_…/status -H "Authorization: Bearer roasos_sk_live_…" curl https://api.roasos.com/v1/jobs/gen_…/result -H "Authorization: Bearer roasos_sk_live_…" ``` ## Today `POST /v1/generations` with `{ "type": "video", "model": "kling-4", "prompt": "…", "options": { … } }`. Today's option names follow the old shape; the table above is API v1.1. `GET https://api.roasos.com/v1/catalog/video/kling-4` is the machine-readable form of this file. ## See also https://docs.roasos.com/models/video/kling-4 · https://api.roasos.com/v1/catalog/video/kling-4 · kling/v4/image-to-video · kling/v4/reference-to-video · kling/v4/text-to-video