# Kling 4.0 UGC (ugc) > Kling 4.0 UGC animates one first frame into a spoken ad clip, or makes the clip from a saved person and product. It renders at 720p or 1080p, from 3 to 30 seconds, and it keeps the person the same across the clip. Status: roasOS API v1.1. Catalog `model-catalog@2026-10-06.v5`, pricing `customer-pricing@2026-11-05.v15`. The endpoint `POST /v1/ugc/kling-4` is live. `POST /v1/generations` has no `ugc` type, so this endpoint is the only path to this model. ## Endpoint POST https://api.roasos.com/v1/ugc/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 A spoken ad from a scene that already shows the person and the set. In reference mode (no scene), name a saved person, a saved product or reference images, and the model makes the ad in one generation. The saved person is sent as an identity element. Kling 4.0 is the only Kling UGC model since 2026-10-29. It replaced the Kling 3 and Kling O3 UGC endpoints, and those endpoints are removed. ## 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 - `standard` - `reference` The worker derives the mode from the media fields of the request. Provider endpoints: `kling/v4/image-to-video` · `kling/v4/reference-to-video`. ## Request fields | field | type | required | default | rule | |---|---|---|---|---| | `aspect_ratio` | enum | no | `9:16` | `9:16`, `16:9`, `1:1`, `21:9`, `auto`; only in `reference` | | `avatar_id` | string | no | — | UUID; only in `reference` | | `avatar_upload` | string | no | — | https URL; ≤ 4,096 characters; only in `reference` | | `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` | | `product_id` | string | no | — | UUID; only in `reference` | | `prompt_mode` | enum | no | — | `wrapped`, `exact` | | `quote_id` | string | no | — | UUID | | `quote_only` | boolean | no | `false` | — | | `references` | string[] | no | — | ≤ 10 items; only in `reference` | | `resolution` | enum | no | `1080p` | `720p`, `1080p` | | `scene_id` | string | no | — | UUID; only in `standard` | | `scene_image` | string | no | — | https URL; ≤ 4,096 characters; only in `standard` | | `script` | string | yes | — | ≥ 1 character; ≤ 10,000 characters | | `second_avatar_upload` | string | no | — | https URL; ≤ 4,096 characters | | `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 - `product_id` — product; resolves to the product image list - `references` — style and appearance references - `scene_id` — first frame — a scene this workspace owns - `scene_image` — first frame — a CDN image | role | items | max size | content types | duration | |---|---|---|---|---| | `references` | ≤ 10 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | | `scene_image` | ≤ 1 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | - Refused: `elements`, `product_images`, `reference_images`, `image_url`, `end_image_url`, `video_urls`, `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 - Standard mode: the platform adds a short facts block to the script. If the script and the block are more than 2,500 characters, the platform removes the block. - Reference mode: do not write `@Image` tags. The platform adds them. - Write the words to be spoken in quotes, with the delivery: says with warm energy: "…". - Write motion as physics: "she lifts the jar to chest height". - Keep the camera static for a talking head. Use one subject and one action. - Lip-sync is best for about five seconds of continuous speech. Split a long script into shots or clips. ## 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. - `mode`: pinned to `image-to-video`. ## Result Result kind `ugc`. Always present: `url`. ```json { "data": { "id": "gen_…", "kind": "ugc", "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/ugc/kling-4 \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-kling-4-0001" \ -H "Content-Type: application/json" \ -d '{"quote_only":true,"script":"Two drops, morning and night. That is the whole routine."}' # → 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/ugc/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…","script":"Two drops, morning and night. That is the whole routine."}' # → 201 { "data": { "id": "gen_…", "kind": "ugc", "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/ugc/kling-4` is the machine-readable form of this file. ## See also https://docs.roasos.com/models/ugc/kling-4 · https://api.roasos.com/v1/catalog/ugc/kling-4 · kling/v4/image-to-video · kling/v4/reference-to-video