Kling's video generation API is not a synchronous interface that returns a video in one request. It creates a task, then you query the status, and finally you download the result. If you write it like Chat Completions, you will usually get stuck at the first step: the request succeeds, but there is no video, only a task record.
This article follows the real integration order and explains Kling API interface generations, authentication, submission, polling, callbacks, downloads, idempotency, and migration in 2026. Paths and fields may change between versions; consult the official documentation before integration.
Note: Kling, Kling AI, and Kuaishou are trademarks of their respective owners. This article is for technical explanation only and implies no affiliation with or agency for those companies.
1. Distinguish the two interface generations first
Kling currently has two interface forms, and mixing them is a common source of errors.
New interfaces place the model version in the path, for example POST /text-to-video/kling-3.0-turbo or POST /text-to-video/kling-2.6. The request body no longer needs model_name, authentication uses an API key in the Bearer header, and the response fields are data.id and data.status.
Legacy interfaces usually live under /v1/videos/..., specify the model with model_name in the request body, authenticate with a JWT generated from AccessKey/SecretKey, and return task_id and task_status. The legacy interface still works, but new projects should not start from it.
The examples below focus on the new interface; a migration checklist for both generations appears at the end.
2. Base URL and authentication
The service addresses in Kling's documentation include:
https://api-singapore.klingai.com: for servers outside mainland China; the official documentation says it replaces the oldapi.klingai.com.https://api-beijing.klingai.com: a Beijing address shown in documentation examples, suitable for deployments inside China.
The regions actually available, the account's applicable scope, and model availability are determined by the console. Do not switch regions casually; tasks and results usually belong to the region where they were submitted.
The authentication header is Authorization: Bearer <API_KEY>, with one space between Bearer and the key. One easy detail to miss: query requests on the new interface also require Content-Type: application/json, even when they use GET.
Keys belong on the server only. Calling directly from a browser, app, or mini program exposes the credential and runs into cross-origin and callback reachability problems. Submit tasks from the backend and let the front end receive only task status.
3. Submit your first video task
First run the chain with the shortest duration and lowest resolution, then add parameters gradually.
export KLING_API_KEY="your-key"
export KLING_BASE_URL="https://api-singapore.klingai.com"
curl -sS -X POST "$KLING_BASE_URL/text-to-video/kling-3.0-turbo" \
-H "Authorization: Bearer $KLING_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A city street after rain, slow camera push-in, cinematic, 16:9",
"settings": {
"resolution": "720p",
"aspect_ratio": "16:9",
"duration": 5
},
"options": {
"external_task_id": "demo-20261019-001",
"callback_url": "https://example.com/kling/callback"
}
}'
A successful response has business code 0, the task ID in data.id, and an initial status usually of submitted:
{
"code": 0,
"message": "",
"request_id": "…",
"data": {
"id": "…",
"status": "submitted",
"create_time": 0,
"update_time": 0,
"external_id": "demo-20261019-001"
}
}
There are several parameter boundaries. For 3.0 Turbo, duration supports 3 to 15 seconds and defaults to 5 seconds; 2.6 commonly offers 5 or 10 seconds. The prompt limit is about 3,072 characters, and the documentation recommends keeping it under 2,500. Resolution, aspect ratio, and audio support vary by model; do not copy one model's parameters directly to another.
4. Poll task status
After receiving the task ID, poll with the query interface:
GET /tasks?task_ids=<task-id>
GET /tasks?external_task_ids=<custom-id>
task_ids and external_task_ids are mutually exclusive, and multiple IDs are separated by commas. The data field in the response is an array of tasks; each task contains id, status, message, create_time, update_time, external_id, outputs, and billing.
There are four states:
submitted: received but not started.processing: generating.succeeded: successful;outputscan be read.failed: failed; checkmessageand the moderation reason.
Do not poll at a fixed high frequency. Start at 5 seconds, back off gradually to 15 to 30 seconds, and set an overall timeout. Video tasks may queue; when they exceed expectations, check concurrency and the resource pack rather than resubmitting immediately.
For reconciliation or backfilling, use the cursor query on POST /tasks, filtering by start_time, end_time, status, and product_type, with a maximum of 500 records per page.
5. Callbacks and signature verification
Pass callback_url when submitting a task, and the platform pushes notifications when the task status changes. Callbacks consume fewer resources than polling, but your endpoint must be publicly reachable, return 200 quickly, and put actual processing on a queue.
On the new interface, the callback body contains id, status, message, outputs, external_id, and billing; the legacy interface uses task_id, task_status, and task_result, and spells the success status as succeed. Do not share one parser between the two formats.
For security, create a Webhook Secret in the console (it starts with whsec_). Callbacks carry three headers: webhook-id, webhook-timestamp, and webhook-signature. The signed content is {webhook-id}.{webhook-timestamp}.{rawBody}, the algorithm is HMAC-SHA256, and the result is Base64 encoded. When verifying, note three points: the timestamp should be within plus or minus 5 minutes, the signature must be computed over the raw request body, and comparison should use a constant-time function. The official platform supports old and new secrets coexisting during a 7-day grace period, which suits smooth rotation.
Callbacks may repeat or arrive out of order. Make processing idempotent by task ID and only move status forward; never overwrite processing back to submitted.
6. Download and store results
For a successful task, the video is in the outputs array. The item with type equal to video contains url, watermark_url, duration, and id. The url is a download address with hotlink protection; embedding it directly in a web page or third-party system may be rejected.
Two hard constraints:
- Result links are cleaned up about 30 days after generation and cannot be treated as permanent CDN addresses.
- Hotlink protection means you should download on the server and transfer the file to your own object storage.
A recommended persistence flow: download immediately after success, check Content-Type and file size, compute a checksum, write to object storage, and associate your own address with the task ID. When distributing externally, use your own signed URL with an expiration time.
7. Idempotency, retries, and concurrency
The most expensive mistake in video tasks is resubmitting after a timeout. A request timeout does not mean the task was not created; it may simply mean the response did not come back.
external_task_id is the main idempotency tool. Generate a stable ID before submission and persist it; after a timeout, look it up with GET /tasks?external_task_ids=... and retry only after confirming that no task exists. The ID must be unique within the account. Do not use random UUIDs as retry keys, or every retry will create a new task.
On concurrency, the official documentation states that only task creation counts toward concurrency; queries do not. The platform does not queue on your behalf, and exceeding the resource pack slots returns 1303. All API keys share the same account concurrency pool. A recommended backoff strategy is exponential backoff starting at 1 second, with a submission queue on the application side that releases work as slots become free.
8. Common error reference
| Business code | HTTP | Meaning | Suggested action |
|---|---|---|---|
| 1002 | 401 | Invalid credential | Check the key, region, and request headers |
| 1103 | 403 | No permission for the interface or model | Confirm the account and resource pack have the model enabled |
| 1101 | 429 | Postpaid arrears | Top up and retry |
| 1102 | 429 | Resource pack exhausted or expired | Buy a resource pack or switch billing mode |
| 1201 | 400 | Invalid parameter value | Read message; check duration, aspect ratio, resolution |
| 1301 | 400 | Content moderation failed | Revise the prompt or assets; do not retry unchanged |
| 1302 | 429 | Requests too frequent | Reduce frequency and apply exponential backoff |
| 1303 | 429 | Concurrency limit exceeded | Queue submissions and wait for slots |
| 1203 | 404 | Resource or model does not exist | Check the path and model version |
| 5002 | 500 | Internal service timeout | Keep the task ID and query later instead of resubmitting |
When troubleshooting, check the HTTP status first, then the business code, then the request_id. Log all three together; this significantly shortens diagnosis time when you contact support.
9. Migration checklist from the legacy interface
- Switch authentication from AccessKey/SecretKey JWT to API key Bearer; legacy interfaces keep JWT compatibility.
- Change paths from
/v1/videos/...to model-scoped forms such as/text-to-video/kling-3.0-turbo. - Remove
model_namefrom the request body; the path determines the model. - Change response fields from
task_idandtask_statustoidandstatus. - Change the success status from
succeedtosucceeded. - Change queries from per-task GET paths to
GET /tasks?task_ids=.... - Change results from
task_result.videosto thetype=videoitem inoutputs. - Separate callback parsers by old and new formats to avoid field mismatches.
- Add logic for 30-day result cleanup and transfer under hotlink protection.
- Complete idempotency with
external_task_id, and run a failure drill covering timeouts, duplicate callbacks, and moderation rejection.
During migration, run both generations in parallel: send canary traffic to the new interface, keep a rollback window on the old one, and retire the old path only after success rate, latency, and billing all meet expectations.
10. Checkpoints for gateway integration
If you integrate through ZSQH AI Gateway, besides the key and base URL, confirm whether the video channel is enabled, whether asynchronous tasks pass through unchanged, whether external_task_id and callbacks are preserved, and how result URLs are delivered. An OpenAI-compatible endpoint for text models cannot be used directly for video tasks.
Start by reviewing models and pricing, then sign up and create a test key. Validate submission, query, and download end to end with one 5-second task before deciding how to shift production traffic.
FAQ
Is the Kling API synchronous or asynchronous?
Asynchronous. Submission returns only a task ID; you poll GET /tasks or receive a callback, and then download the video from outputs after success.
Should the base URL be Singapore or Beijing?
It depends on server location, account ownership, and where the model is available. Both addresses appear in official documentation; confirm in the console before integrating, and keep task submission and queries in the same region.
What if a task stays in processing?
Check concurrency slots and whether the resource pack is sufficient, then confirm whether the task is queued. If it exceeds expectations, query by task ID rather than resubmitting; contact support with the request_id if needed.
Can the result URL be placed directly on a website or mini program?
Not recommended. The link uses hotlink protection and is cleaned up after about 30 days. Download on the server, transfer to object storage, and serve it through your own signed URL.
Does retrying a failed task charge twice?
It depends on the failure reason and the platform's billing rules. Moderation failures usually should not be retried unchanged; after a network timeout, look up the task by external_task_id and submit again only after confirming it was not created. Read the billing documentation and validate with small tasks before launch.
Related reading:
