Kling 3.0

EndpointCapabilityRequired fields
POST /kling/text-to-video/kling-3.0Text to videoprompt
POST /kling/image-to-video/kling-3.0Image to video (first frame, optional last frame and elements)contents (with a first_frame)
GET /kling/tasks?task_ids={id}Query a tasktask_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/kling and authenticate with Authorization: Bearer $MODELGO_API_KEY (no Kling JWT signing).

1. Create a task

Text to video

bash
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

bash
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

json
{
  "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

FieldApplies toDescription
prompttext-to-videoRequired, ≤ 3072 characters
contentsimage-to-videoRequired array, see below
settingsallGeneration settings, see below
optionsallExtra options, see below

contents[] (image-to-video)

typeFieldsDescription
first_frameurlRequired, 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_frameurlOptional, at most one. Must be sent together with first_frame; a last frame alone returns 400
prompttextOptional, at most one, ≤ 3072 characters
elementelement_id, idOptional, up to 3; element_id is the Kling-side subject ID, id is unique within the task

settings

FieldValuesDescription
resolution720p / 1080p / 4kTier, default 720p; unstated is billed as 720P. Other values return 400
audionative / offWhether to generate native audio, default off. native switches to the audio price tier
durationinteger 3–15Length in seconds, default 5
aspect_ratio16:9 / 9:16 / 1:1text-to-video only; image to video follows the first frame
multi_shotboolMulti-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

FieldDescription
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_idAccepted 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, element and watermark_info.enabled: true are routed only to supplier channels that forward them as sent; when none is available the call returns 400 (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 to settings.duration (default 5), otherwise creation returns 400.
  • Automatic shots: any other prompt is split into shots by the model.

Tiers

resolutionOutput
720p1280×720 (by ratio), default
1080p1920×1080 (by ratio)
4k4K (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 4k request goes only to a supplier that can render 4K and is never silently downgraded; when no 4K supplier is available, creation returns 400 and 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}

bash
curl "https://api.modelgo.ai/kling/tasks?task_ids=gw_6dce033e-9243-4a64-9c57-73d08a8e379a" \
  -H "Authorization: Bearer $MODELGO_API_KEY"

When finished:

json
{
  "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 failure message gives the reason and the task is not billed.
  • Each request queries one task: pass a single ID in task_ids (a comma-separated list or external_task_ids returns 400).
  • Generation usually takes 1–3 minutes; poll every 5–10 seconds with backoff.
  • outputs[].url points at the gateway content endpoint and needs the API key to download; duration is the delivered length in seconds.

4. Download the video

GET https://api.modelgo.ai/v1/videos/{id}/content

bash
curl https://api.modelgo.ai/v1/videos/gw_6dce033e-9243-4a64-9c57-73d08a8e379a/content \
  -H "Authorization: Bearer $MODELGO_API_KEY" -o kling.mp4

Returns 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)

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 duration is pre-authorized (frozen); on completion the task settles on the delivered seconds. Some channels deliver about 1 second more (5 requested, 6 delivered); outputs[].duration is 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

SymptomCauseFix
Create returns 400settings.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 tierFix per the parameter tables (the response message names the field)
Create returns 400, error_class=provider_unsupportedInline base64 image, or no supplier channel currently forwards multi_shot / element / watermark_info.enabled=trueUse a public URL for images; drop the field or retry later
status=failedThe upstream could not fetch the first frame, or generation failedUse a directly downloadable public link
Poll returns 404 with code=1203task_ids is not a task created by this keyUse data.id from the create response
/content returns 409 / 404Task unfinished / artifact expiredPoll until succeeded; download promptly