Kling 3.0 Turbo
kling-3.0-turbo creates 3–15 second videos with audio from text or a single first-frame image, at 720p or 1080p.
To migrate a client using the official Turbo protocol, set base_url to https://api.aivideoapi.ai and replace its API key with your platform API key. Keep the endpoint paths and request/response field names below. Input limits and credit billing follow this page.
| Method and path | Purpose |
|---|---|
POST /text-to-video/kling-3.0-turbo | Text-to-video |
POST /image-to-video/kling-3.0-turbo | First-frame image-to-video |
GET /tasks | Query by task IDs or external IDs |
POST /tasks | Filter and paginate tasks |
All endpoints use Authorization: Bearer YOUR_PLATFORM_API_KEY; JSON requests use Content-Type: application/json. This protocol uses the paths above directly, without adding /v1.
Create a task
Text-to-video
A minimal request uses the default 720p, 5 seconds, 16:9, with watermark disabled. Audio is always generated; there is no audio switch.
curl -X POST 'https://api.aivideoapi.ai/text-to-video/kling-3.0-turbo' \
-H 'Authorization: Bearer YOUR_PLATFORM_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"prompt":"A kitten runs through a moonlit garden, with rustling leaves and soft footsteps."}'
For vertical 1080p output, a callback, and a watermarked copy:
{
"prompt": "A girl watches the passing landscape from a train window, with the gentle sound of the train.",
"settings": {"resolution": "1080p", "duration": 5, "aspect_ratio": "9:16"},
"options": {
"external_task_id": "turbo-text-001",
"callback_url": "https://app.example.com/webhooks/video",
"watermark_info": {"enabled": true}
}
}
The remaining creation examples are complete JSON bodies. Use the matching text or image endpoint. Replace example media and callback URLs with your own reachable URLs.
First-frame image-to-video
Send exactly one first_frame and optionally one prompt to POST /image-to-video/kling-3.0-turbo. Output aspect ratio follows the image; omit settings.aspect_ratio.
{
"contents": [
{"type": "prompt", "text": "The kitten looks toward the camera as a breeze moves its fur, with birdsong in the distance."},
{"type": "first_frame", "url": "https://media.example.com/kitten.jpg"}
],
"settings": {"resolution": "720p", "duration": 5},
"options": {"external_task_id": "turbo-image-001"}
}
A first frame without a prompt is also accepted:
{
"contents": [{"type": "first_frame", "url": "https://media.example.com/kitten.jpg"}]
}
Base64 first frame
contents[].url also accepts PNG/JPEG Base64, with or without a data URL prefix. Replace the placeholder below with your full image data. The bytes are preserved during temporary upload; the platform does not resize or compress the image. Prefer a URL for large files.
{
"contents": [
{"type": "prompt", "text": "A slow camera push toward the subject, with soft ambient sound."},
{"type": "first_frame", "url": "data:image/jpeg;base64,REPLACE_WITH_FULL_IMAGE_BASE64"}
],
"settings": {"resolution": "1080p", "duration": 8},
"options": {"external_task_id": "turbo-base64-001"}
}
Explicit shots
Use the literal format 镜头 n, seconds, description;, with ASCII commas and semicolons, including for English descriptions. Number 1–6 shots consecutively from 1. Each duration must be an integer of at least 1 second, and the total must equal settings.duration. Keep each shot description within 512 characters.
The format automatically enables explicit shot planning. There is no public multi_shot setting; ordinary prompts use single-shot generation.
{
"prompt": "镜头 1, 2, Wide shot of a moonlit garden with rustling leaves;镜头 2, 3, Close-up of a kitten looking toward the moon with soft footsteps;",
"settings": {"resolution": "720p", "duration": 5, "aspect_ratio": "16:9"},
"options": {"external_task_id": "turbo-shots-001"}
}
The same shot format works in an image task's prompt item:
{
"contents": [
{"type": "prompt", "text": "镜头 1, 2, The kitten turns toward the camera;镜头 2, 3, The kitten walks away through the garden;"},
{"type": "first_frame", "url": "https://media.example.com/kitten.jpg"}
],
"settings": {"resolution": "1080p", "duration": 5},
"options": {"external_task_id": "turbo-image-shots-001", "watermark_info": {"enabled": true}}
}
Parameters and input limits
| Field | Accepted values and behavior |
|---|---|
prompt | Required text for text-to-video; write both positive and negative descriptions here |
contents | Required for image-to-video: one first_frame and at most one prompt |
contents[].type | first_frame with url, or prompt with text |
settings.resolution | 720p (default) or 1080p |
settings.duration | Integer from 3 to 15 seconds; default 5 |
settings.aspect_ratio | Text-to-video only: 16:9 (default), 9:16, or 1:1 |
options.external_task_id | Optional client ID; see idempotency below |
options.callback_url | Optional HTTP(S) endpoint for state-change notifications |
options.watermark_info.enabled | Boolean, default false; enables an additional watermarked copy |
Turbo does not support a last frame, reference images/videos, video editing, elements, 4K, a separate negative prompt field, or an audio switch.
Use JPEG/JPG/PNG images without transparency, with both dimensions between 300 and 8000 pixels, aspect ratio between 1:2.5 and 2.5:1, and file size no greater than 10 MB. Keep ordinary prompts within 2500 characters. These service limits are narrower than the official Turbo image limit of 50 MB and text-to-video prompt limit of 3072 characters.
The platform does not add image-size or prompt-length checks, compress images, or truncate text. Inputs are submitted unchanged apart from protocol conversion; generation can reject inputs outside the limits, and returns a cleaned error. Explicit shot descriptions should stay within 512 characters to avoid shortening during generation.
The current deployment limits the entire JSON request body to 4.5 MB, including Base64 overhead. Oversized requests can be rejected before the API runs. Use HTTP(S) URLs for larger images. See request body limits.
Media URLs must allow file download without login. Callback URLs must be reachable from the API server and accept POST directly. Both must use HTTP(S) without a username or password. Callback redirects are not followed.
Idempotency and creation response
Within the same account and model, retrying the same options.external_task_id with identical parameters returns the existing task without another charge. Different parameters, including changing text-to-video to image-to-video, produce a conflict. Use a new ID for a new task. IDs are scoped by model; use globally unique IDs across your integration to avoid ambiguity in queries. An omitted or empty external ID does not provide idempotency.
Successful creation returns an asynchronous task summary:
{
"code": 0,
"message": "SUCCEED",
"request_id": "81bb383c-bf77-41dc-b123-dc5f0688a064",
"data": {
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "submitted",
"create_time": 1789603200000,
"update_time": 1789603200000,
"external_id": "turbo-text-001"
}
}
external_id appears only when supplied. Timestamps are Unix milliseconds. Creation does not include outputs, billing, or task-level message. An idempotent retry can return a later status.
Query by ID
Use GET /tasks and specify exactly one of task_ids or external_task_ids. Each accepts comma-separated IDs.
curl --get 'https://api.aivideoapi.ai/tasks' \
-H 'Authorization: Bearer YOUR_PLATFORM_API_KEY' \
--data-urlencode 'task_ids=29bd04f8-3c15-4374-a364-4b484782d235'
curl --get 'https://api.aivideoapi.ai/tasks' \
-H 'Authorization: Bearer YOUR_PLATFORM_API_KEY' \
--data-urlencode 'external_task_ids=turbo-text-001,turbo-image-001'
The shared endpoint returns your matching Turbo and Omni tasks. If both models use the same external ID, both tasks are returned. Missing tasks and other users' tasks are omitted; no matches returns data: []. A task is returned once even if its ID is repeated. Queries read saved platform records; they do not trigger generation or polling.
Processing response
{
"code": 0,
"message": "SUCCEED",
"request_id": "d482570f-e19c-4d82-af57-4959ef8bf837",
"data": [{
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "processing",
"create_time": 1789603200000,
"update_time": 1789603230000,
"external_id": "turbo-text-001",
"message": "",
"outputs": [],
"billing": []
}]
}
submitted means accepted or waiting; processing covers generation, recording the result, and final credit settlement. Both have empty outputs and billing.
Success response
This example corresponds to the 1080p, 5-second text task above, with an account multiplier of 1.
{
"code": 0,
"message": "SUCCEED",
"request_id": "9ebfc933-3d04-424b-9f11-707d0c701ce1",
"data": [{
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "succeeded",
"create_time": 1789603200000,
"update_time": 1789603320000,
"external_id": "turbo-text-001",
"message": "",
"outputs": [{
"type": "video",
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"url": "https://media.example.com/results/turbo-text-001.mp4?signature=example",
"watermark_url": "https://media.example.com/results/turbo-text-001-watermarked.mp4?signature=example",
"duration": "5"
}],
"billing": [{"charge_type": "unit", "amount": "192.31", "package_type": "video"}]
}]
}
Use the exact url and optional watermark_url, including all signature parameters. The platform passes these addresses through without replacing the domain or copying the files. Download promptly; URLs can expire. Task and billing retention does not extend media availability, and the platform does not guarantee at least 30 days of download availability. duration and billing[].amount are decimal strings.
Failure response
The outer code=0 means the query succeeded; inspect the task's status for its outcome.
{
"code": 0,
"message": "SUCCEED",
"request_id": "42685723-917a-4ea7-82ef-cdf7c03aeaa9",
"data": [{
"id": "7689f980-0f92-4d31-bc7b-bc848d051d70",
"status": "failed",
"create_time": 1789603200000,
"update_time": 1789603260000,
"external_id": "turbo-failed-001",
"message": "Video generation could not be completed.",
"outputs": [],
"billing": []
}]
}
Filter and paginate
Send POST /tasks. By default, it queries the previous 30 days, ending now, with up to 100 tasks per page. limit accepts integers from 1 to 500. start_time and end_time accept Unix milliseconds; digit-only millisecond timestamp strings remain supported.
{
"start_time": 1789603200000,
"end_time": 1789689600000,
"limit": 100,
"filters": [
{"key": "status", "values": ["succeeded"]},
{"key": "product_type", "values": ["video"]}
]
}
status accepts submitted, processing, succeeded, and failed. product_type supports the official video, image, and try_on values, but this endpoint currently has only Turbo/Omni video tasks; selecting only other product types returns no tasks.
Example last page:
{
"code": 0,
"message": "SUCCEED",
"request_id": "3d6a01c0-a624-4934-9361-15d09a4c1586",
"data": {
"result": [{
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "succeeded",
"create_time": 1789603200000,
"update_time": 1789603320000,
"external_id": "turbo-text-001",
"message": "",
"outputs": [{"type": "video", "id": "29bd04f8-3c15-4374-a364-4b484782d235", "url": "https://media.example.com/results/turbo-text-001.mp4?signature=example", "duration": "5"}],
"billing": [{"charge_type": "unit", "amount": "192.31", "package_type": "video"}]
}],
"count": 1,
"next_cursor": "",
"has_more": false
}
}
When has_more=true, pass the returned next_cursor unchanged:
{"cursor": "REPLACE_WITH_NEXT_CURSOR", "limit": 100}
The cursor preserves the time window, filters, and model scope; do not reconstruct it. Tasks are ordered newest first, using task ID to break equal creation times. Previously issued Omni cursors continue querying only Omni; new cursors include both models. count is the number of tasks in the current page.
Callbacks
Set options.callback_url at creation. Turbo sends one event for each observed state change: submitted, processing, and succeeded or failed. Intermediate states that were never observed are not fabricated. Duplicate queries or idempotent creation retries do not create additional events.
The body is a single task object, with the same fields as one query result. There is no code, request_id, or data wrapper. Each event preserves the task snapshot at that transition. A success event is created only after final credit settlement.
Submitted callback example:
{
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "submitted",
"create_time": 1789603200000,
"update_time": 1789603200000,
"external_id": "turbo-text-001",
"message": "",
"outputs": [],
"billing": []
}
A processing event uses the same shape, with its status and update time changed. Success example:
{
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"status": "succeeded",
"create_time": 1789603200000,
"update_time": 1789603320000,
"external_id": "turbo-text-001",
"message": "",
"outputs": [{
"type": "video",
"id": "29bd04f8-3c15-4374-a364-4b484782d235",
"url": "https://media.example.com/results/turbo-text-001.mp4?signature=example",
"watermark_url": "https://media.example.com/results/turbo-text-001-watermarked.mp4?signature=example",
"duration": "5"
}],
"billing": [{"charge_type": "unit", "amount": "192.31", "package_type": "video"}]
}
A failed callback has status="failed", an explanatory message, and empty outputs and billing, as in the failure query object above.
Signing and verification
Ask your account administrator to configure a Turbo Webhook Secret, separate from the platform API key. It is not a creation-request field. Signing uses the current secret when each delivery is attempted. Regular rotation signs with both the new key and the preceding key for seven days; emergency revocation removes the old key immediately. Removing the configuration disables signing, including for pending events.
| Header | Value |
|---|---|
webhook-id | Stable event ID across retries; each state change has its own ID |
webhook-timestamp | Unix seconds for this delivery attempt |
webhook-signature | One or more space-separated v1,BASE64_SIGNATURE values |
Use Standard Webhooks verification on the raw request body. For example, with the standardwebhooks JavaScript package:
import { Webhook } from "standardwebhooks";
const rawBody = await request.text();
const verifiedTask = new Webhook(process.env.TURBO_WEBHOOK_SECRET).verify(rawBody, {
"webhook-id": request.headers.get("webhook-id"),
"webhook-timestamp": request.headers.get("webhook-timestamp"),
"webhook-signature": request.headers.get("webhook-signature"),
});
// Persist this event idempotently before acknowledging it.
For a custom verifier, remove the whsec_ prefix and Base64-decode the secret. Sign webhook-id.webhook-timestamp.rawBody with HMAC-SHA256, then Base64-encode the digest. Accept a constant-time match against any supported v1 signature, check a recent timestamp window (typically five minutes), and deduplicate by event ID. Never reserialize parsed JSON for verification.
Without a configured secret, the three webhook-* headers are omitted. For unsigned deliveries, confirm the current task through authenticated GET /tasks before applying business changes. Make status updates idempotent and avoid regressing a newer terminal state.
Delivery and retries
Return HTTP 2xx within 10 seconds after durably saving or enqueueing the event. Process video downloads asynchronously. Timeout, network error, non-2xx, and redirects count as failed deliveries.
- Attempt 1: when the event becomes available for delivery.
- Attempt 2: scheduled 3 minutes after the first failure.
- Attempt 3: scheduled 10 minutes after the second failure.
Each event receives at most three attempts. Per-task events are delivered in order; an older event's retries can delay later callbacks, but do not delay generation or settlement. Retries keep the event ID and body, with a fresh timestamp and signature. Actual delivery may occur later than the scheduled time. After attempts are exhausted, query the task to reconcile your records.
Callback failure never changes successful generation to failure and never causes a refund or another generation request.
Billing
- 720p: 30.8 credits/second, for text-to-video and first-frame image-to-video, including audio.
- 1080p: 38.5 credits/second, for text-to-video and first-frame image-to-video, including audio.
- Rates above use the default account multiplier of
1and are displayed to one decimal place. Settlement uses the configured rate before display rounding. - Credits are precharged using the requested duration and reconciled against actual successful usage:
round(round(rate × seconds, 2) × accountMultiplier, 2). Each task retains its rate and multiplier snapshot. - At the default multiplier, 5 seconds costs 153.85 credits at 720p or 192.31 credits at 1080p. The rounded display rate is not used to calculate these totals.
- A successful task's
billing[].amountis the final platform-credit charge as a decimal string, withcharge_type="unit"andpackage_type="video". - Confirmed failures refund the precharge once. An unknown submission or task state does not trigger automatic resubmission or refund. Errors after generation succeeds, including settlement retries and callback failures, cannot enter the failure-refund path. Cancellation is unsupported.