Kling 3.0
| Endpoint | Capability | Required fields |
|---|---|---|
POST /kling/text-to-video/kling-3.0 | Text to video | prompt |
POST /kling/image-to-video/kling-3.0 | Image to video (first frame, optional last frame and elements) | contents (with a first_frame) |
GET /kling/tasks?task_ids={id} | Query a task | task_ids |
ModelGo accepts the paths and request/response shapes of Kling's official 3.0 API (settings, options, contents[], …); the gateway routes to a supplier and bills. Which supplier renders the clip is invisible to the caller.
With Kling's official samples, replace the API host with
https://api.modelgo.ai/klingand authenticate withAuthorization: Bearer $MODELGO_API_KEY(no Kling JWT signing).
1. Create a task
Text to video
curl https://api.modelgo.ai/kling/text-to-video/kling-3.0 \
-H "Authorization: Bearer $MODELGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A small red ball rolling slowly across a wooden table, soft daylight",
"settings": {
"resolution": "720p",
"aspect_ratio": "16:9",
"duration": 5,
"audio": "native"
}
}'Image to video
curl https://api.modelgo.ai/kling/image-to-video/kling-3.0 \
-H "Authorization: Bearer $MODELGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{"type": "prompt", "text": "The puppy slowly turns its head"},
{"type": "first_frame", "url": "https://example-cdn.com/dog.jpg"}
],
"settings": {"resolution": "1080p", "duration": 5}
}'Response
{
"code": 0,
"message": "SUCCEED",
"request_id": "gw_6dce033e-9243-4a64-9c57-73d08a8e379a",
"data": {
"id": "gw_6dce033e-9243-4a64-9c57-73d08a8e379a",
"status": "submitted",
"create_time": 1788773081000,
"update_time": 1788773081000
}
}data.id is the gateway task ID; use it to poll and to fetch the content. Timestamps are in milliseconds.
2. Parameters
Request body
| Field | Applies to | Description |
|---|---|---|
prompt | text-to-video | Required, ≤ 3072 characters |
contents | image-to-video | Required array, see below |
settings | all | Generation settings, see below |
options | all | Extra options, see below |
contents[] (image-to-video)
type | Fields | Description |
|---|---|---|
first_frame | url | Required, at most one. First frame: a publicly downloadable http(s) URL. The current supplier channels do not take inline base64 images (bare base64 or a data: URI) and return 400 (error_class=provider_unsupported) |
last_frame | url | Optional, at most one. Must be sent together with first_frame; a last frame alone returns 400 |
prompt | text | Optional, at most one, ≤ 3072 characters |
element | element_id, id | Optional, up to 3; element_id is the Kling-side subject ID, id is unique within the task |
settings
| Field | Values | Description |
|---|---|---|
resolution | 720p / 1080p / 4k | Tier, default 720p; unstated is billed as 720P. Other values return 400 |
audio | native / off | Whether to generate native audio, default off. native switches to the audio price tier |
duration | integer 3–15 | Length in seconds, default 5 |
aspect_ratio | 16:9 / 9:16 / 1:1 | text-to-video only; image to video follows the first frame |
multi_shot | bool | Multi-shot switch, see "Multi-shot" below. A prompt written as 镜头 n, seconds, description; with the field omitted is treated as the official default true; for a plain-text prompt the gateway sends nothing and the supplier's default applies. false makes the 镜头 text ordinary prompt text |
options
| Field | Description |
|---|---|
watermark_info | {"enabled": true/false}, forwarded to the supplier as sent; it does not change the price. enabled: true is only available on supplier channels that forward the field; other channels return 400 (error_class=provider_unsupported) |
callback_url / external_task_id | Accepted but not honoured: the gateway sends no callback, poll by id |
- Fields outside the tables above are refused at creation (HTTP
400, naming the field) rather than ignored. multi_shot: true,elementandwatermark_info.enabled: trueare routed only to supplier channels that forward them as sent; when none is available the call returns400(error_class=provider_unsupported) — they are never silently dropped and billed as a plain clip. These fields do not change the unit price.
Multi-shot
With settings.multi_shot set to true, the shots are written in prompt:
- Custom shots: write them as
镜头 n, seconds, description;— for example镜头 1, 3, a cat blinks by the window; 镜头 2, 3, the cat stretches;. Shots are numbered from 1 in order, at most 6, each description ≤ 512 characters, and the shot lengths must add up tosettings.duration(default 5), otherwise creation returns400. - Automatic shots: any other prompt is split into shots by the model.
Tiers
resolution | Output |
|---|---|
720p | 1280×720 (by ratio), default |
1080p | 1920×1080 (by ratio) |
4k | 4K (by ratio), served only by suppliers that support 4K, priced separately |
- Only these three tiers are offered. The gateway routes by the tiers each supplier can deliver: a
4krequest goes only to a supplier that can render 4K and is never silently downgraded; when no 4K supplier is available, creation returns400and nothing is charged.
First-frame image requirements (image-to-video)
- A direct link the upstream server can
GET: no auth, no redirects, no dependence on Referer / Cookie; JPG / PNG, ≤ 10MB, width and height ≥ 300px, aspect ratio 1:2.5–2.5:1. - A failed image fetch fails the task (
status=failed) with no charge. Use your own object storage or CDN address.
3. Poll a task
GET https://api.modelgo.ai/kling/tasks?task_ids={id}
curl "https://api.modelgo.ai/kling/tasks?task_ids=gw_6dce033e-9243-4a64-9c57-73d08a8e379a" \
-H "Authorization: Bearer $MODELGO_API_KEY"When finished:
{
"code": 0,
"message": "SUCCEED",
"request_id": "gw_6dce033e-9243-4a64-9c57-73d08a8e379a",
"data": [
{
"id": "gw_6dce033e-9243-4a64-9c57-73d08a8e379a",
"status": "succeeded",
"create_time": 1788773081000,
"update_time": 1788773250000,
"outputs": [
{
"type": "video",
"id": "gw_6dce033e-9243-4a64-9c57-73d08a8e379a",
"url": "https://api.modelgo.ai/v1/videos/gw_6dce033e-9243-4a64-9c57-73d08a8e379a/content",
"duration": "6"
}
]
}
]
}status:submitted→processing→succeeded/failed. On failuremessagegives the reason and the task is not billed.- Each request queries one task: pass a single ID in
task_ids(a comma-separated list orexternal_task_idsreturns400). - Generation usually takes 1–3 minutes; poll every 5–10 seconds with backoff.
outputs[].urlpoints at the gateway content endpoint and needs the API key to download;durationis the delivered length in seconds.
4. Download the video
GET https://api.modelgo.ai/v1/videos/{id}/content
curl https://api.modelgo.ai/v1/videos/gw_6dce033e-9243-4a64-9c57-73d08a8e379a/content \
-H "Authorization: Bearer $MODELGO_API_KEY" -o kling.mp4Returns a video/mp4 byte stream and supports Range. Only the API key that owns the task (or a same-tenant console session) can read it; 409 if unfinished, 404 if expired or unknown.
5. Complete example (Python)
import os, time, requests
BASE = "https://api.modelgo.ai/kling"
H = {"Authorization": f"Bearer {os.environ['MODELGO_API_KEY']}"}
def generate(path: str, body: dict, out: str, timeout: int = 600) -> None:
r = requests.post(f"{BASE}/{path}/kling-3.0", json=body, headers=H, timeout=30)
r.raise_for_status()
task_id = r.json()["data"]["id"]
deadline = time.time() + timeout
while True:
if time.time() > deadline:
raise TimeoutError(task_id)
task = requests.get(f"{BASE}/tasks", params={"task_ids": task_id}, headers=H, timeout=30).json()["data"][0]
if task["status"] == "succeeded":
break
if task["status"] == "failed":
raise RuntimeError(task.get("message", "generation failed"))
time.sleep(8)
url = task["outputs"][0]["url"]
with requests.get(url, headers=H, stream=True, timeout=120) as c:
c.raise_for_status()
with open(out, "wb") as f:
for chunk in c.iter_content(1 << 20):
f.write(chunk)
generate("text-to-video", {"prompt": "A small red ball rolling slowly across a wooden table", "settings": {"resolution": "720p", "duration": 5, "audio": "native"}}, "t2v.mp4")
generate("image-to-video", {"contents": [{"type": "prompt", "text": "The puppy slowly turns its head"}, {"type": "first_frame", "url": "https://example-cdn.com/dog.jpg"}], "settings": {"resolution": "1080p", "duration": 5}}, "i2v.mp4")6. Billing
- Billed by video seconds × unit price; the price is set by three dimensions: input mode (text / image), tier (
720p/1080p/4k) and whether audio is generated (audio). - At creation the requested
durationis pre-authorized (frozen); on completion the task settles on the delivered seconds. Some channels deliver about 1 second more (5 requested, 6 delivered);outputs[].durationis the figure to rely on. - When no duration is stated the default is pre-authorized (Kling 5 seconds) and the same default is sent to the supplier; settlement uses the delivered seconds reported by the supplier, rounded to a whole second (5.041 → 5, 5.5 → 6), which can differ from the requested length by ±1 second.
- A rejected creation (
400) or a failed generation (failed) is not billed; the pre-authorization is released. - Unit prices per tier are the ones in the console "Model list".
Error responses
A failed request keeps its HTTP status, and the body matches the official shape: {"code": 1201, "message": "…", "request_id": "…"}. code is a business code from the official error table, chosen by HTTP status: 400→1201, 401→1000, 403→1103, 404→1203, 405→1202, 429→1302, 500→5000, 503→5001, 504→5002; message names the cause. A generation that fails is not a request error: it still returns code=0 with task status=failed and the reason in message.
Common errors
| Symptom | Cause | Fix |
|---|---|---|
Create returns 400 | settings.resolution is not 720p/1080p/4k; settings.audio is not native/off; duration outside 3–15; text-to-video without prompt; image-to-video without first_frame or with only last_frame; malformed shots or shot lengths ≠ duration; a field outside the tables above; no supplier can render the requested tier | Fix per the parameter tables (the response message names the field) |
Create returns 400, error_class=provider_unsupported | Inline base64 image, or no supplier channel currently forwards multi_shot / element / watermark_info.enabled=true | Use a public URL for images; drop the field or retry later |
status=failed | The upstream could not fetch the first frame, or generation failed | Use a directly downloadable public link |
Poll returns 404 with code=1203 | task_ids is not a task created by this key | Use data.id from the create response |
/content returns 409 / 404 | Task unfinished / artifact expired | Poll until succeeded; download promptly |