| name | kling-image-to-video |
| description | Generate AI videos from static images using Kling's Image-to-Video API with audio-visual sync. Use this skill whenever the user wants to animate an image, convert a photo to video, create an AI video from a picture, add motion to a still image, generate video from image with camera movement or voice, or use Kling image2video — even if they don't say "Kling" explicitly. |
| license | MIT |
Kling Image-to-Video (Audio-Visual Sync)
Generate high-quality videos from static images using Kling AI. Supports multiple model versions (kling-v1 through kling-v2-6), professional quality mode, camera control, motion brush trajectories, end-frame control, and voice synthesis. Videos can be 5s or 10s.
This is an async skill: submitting the task returns a task_id immediately; the video becomes available only after polling until task_status is succeed.
Read references/create-task-api.md for the full submit-task specification and Edge Function code.
Read references/query-task-api.md for the full query-task specification and Edge Function code.
End-to-End Workflow
Generation-time usage (Agent direct call)
Use this pattern when working directly as an agent (no application frontend needed).
const apiKey = process.env["INTEGRATIONS_API_KEY"]!;
async function submitImage2VideoTask(params: {
image: string; // Required: Base64 string or accessible URL (jpg/jpeg/png, max 10MB)
prompt?: string; // Optional: text description, max 2500 chars
model_name?: string; // Optional: default "kling-v2-6"
mode?: "std" | "pro"; // Optional: default "pro"
duration?: "5" | "10"; // Optional: default "5"
image_tail?: string; // Optional: end-frame control image
negative_prompt?: string;
cfg_scale?: number; // [0,1], not supported in v2.x
voice_list?: { voice_id: string }[];
sound?: "on" | "off";
static_mask?: string; // Optional: static motion brush mask image (Base64 or URL)
camera_control?: {
type: "simple" | "down_back" | "forward_up" | "right_turn_forward" | "left_turn_forward";
config?: { horizontal?: number; vertical?: number; pan?: number; tilt?: number; roll?: number; zoom?: number };
};
external_task_id?: string;
callback_url?: string;
}): Promise<string> {
const response = await fetch("https://api-eLMlJj3KJD89@api-singapore.klingai.com/v1/videos/image2video", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Gateway-Authorization": `Bearer ${apiKey}`,
},
body: JSON.stringify(params),
});
if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
const json = await response.json();
if (json.code !== 0) throw new Error(`API error ${json.code}: ${json.message}`);
return json.data.task_id;
}
async function pollUntilDone(taskId: string): Promise<{ id: string; url: string; duration: string }[]> {
const POLL_INTERVAL_MS = 7000;
const TIMEOUT_MS = 10 * 60 * 1000;
const deadline = Date.now() + TIMEOUT_MS;
while (Date.now() < deadline) {
await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
const res = await fetch(
`https://api-rLobzpqX85m9@api-singapore.klingai.com/v1/videos/image2video/${taskId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Gateway-Authorization": `Bearer ${apiKey}`,
},
}
);
if (!res.ok) throw new Error(`Poll HTTP error: ${res.status}`);
const json = await res.json();
if (json.code !== 0) throw new Error(`Poll API error ${json.code}: ${json.message}`);
const { task_status, task_status_msg, task_result } = json.data;
if (task_status === "succeed") return task_result.videos;
if (task_status === "failed") throw new Error(`Task failed: ${task_status_msg}`);
}
throw new Error(`Task ${taskId} timed out after 10 minutes`);
}
async function generateVideo(image: string, prompt?: string) {
const taskId = await submitImage2VideoTask({ image, prompt });
console.log(`Task submitted: ${taskId}`);
const videos = await pollUntilDone(taskId);
return videos;
}
Generation-time file download (required):
The video URL returned by the generation API is an ephemeral CDN link with a 30-day TTL. After obtaining the URL during generation (Agent direct call scenario), immediately use the Bash tool to download the file locally so the user can view the result.
curl -L -o ./output_video.mp4 "<generated video URL>"
Complete generation-time workflow (including download step):
- Call
submitImage2VideoTask to obtain the task_id
- Call
pollUntilDone to poll until status is succeed and obtain the video URL
- Use the Bash tool to run
curl -L -o <local-path>.mp4 "<url>" to download the video locally
- Inform the user of the file path where the video has been saved
Note: The upstream CDN link expires after 30 days; download immediately after obtaining the URL.
Post-generation usage (in-app via Edge Function)
For production apps, use two Edge Functions — one per endpoint — so the platform API key never reaches the browser. After the query Edge Function retrieves the video URL, transfer it to Supabase Storage for persistence.
Read references/create-task-api.md for the complete submit Edge Function (edge-functions/kling-submit-image2video.ts).
Read references/query-task-api.md for the complete query Edge Function (edge-functions/kling-query-image2video.ts) including Supabase Storage transfer.
Frontend polling loop:
const { data: submitData, error: submitError } = await supabase.functions.invoke(
"kling-submit-image2video",
{ body: { image, prompt, model_name: "kling-v2-6", mode: "pro", duration: "5" } }
);
if (submitError) throw submitError;
const taskId: string = submitData.data.task_id;
const POLL_INTERVAL_MS = 7000;
const TIMEOUT_MS = 10 * 60 * 1000;
const deadline = Date.now() + TIMEOUT_MS;
while (Date.now() < deadline) {
await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
const { data: queryData, error: queryError } = await supabase.functions.invoke(
,
{ : { : taskId } }
);
(queryError) queryError;
{ task_status, task_status_msg, task_result } = queryData.;
(task_status === ) {
task_result.;
}
(task_status === ) ();
}
();
Parameter Summary
For full parameter tables, see references/create-task-api.md (submit) and references/query-task-api.md (query).
| Parameter | Type | Required | Description |
|---|
image | string | Yes | Reference image (Base64 or URL), jpg/jpeg/png, ≤10MB, ≥300px, aspect ratio 1:2.5~2.5:1 |
prompt | string | No | Positive text prompt, ≤2500 characters |
model_name | string | No | Model version, default kling-v2-6 |
mode | string | No | Generation mode: std / pro, default pro |
duration | string | No | Video duration (seconds): 5 or 10, default 5 |
image_tail | string | No | End-frame control image, same format requirements as image |
static_mask | string | No | Static motion brush mask image (Base64 or URL); aspect ratio must match image |
camera_control | object | No | Camera movement control; mutually exclusive with image_tail and dynamic_masks/static_mask |
camera_control.type | string | No | Preset type: simple (custom) / down_back / forward_up / right_turn_forward / left_turn_forward |
camera_control.config.horizontal | number | No | Left/right translation [-10, 10]; only when type=simple, only one config field may be non-zero |
camera_control.config.vertical | number | No | Up/down translation [-10, 10] |
camera_control.config.pan | number |
Notes
- Key security:
INTEGRATIONS_API_KEY must only be read server-side in Edge Functions; never expose it to the frontend.
- Error handling: Always handle 429 (quota exceeded) and 402 (insufficient balance).
- Billing: The submit task endpoint (
api-eLMlJj3KJD89) has billing enabled — original price ¥100.80, discount price ¥84.00 (per 84 billing units). The query endpoint (api-rLobzpqX85m9) is free. Avoid re-submitting duplicate tasks to minimise unnecessary charges.
- Mutually exclusive parameters:
image+image_tail, dynamic_masks/static_mask, and camera_control cannot be used simultaneously.
- Base64 format: Do not include the
data:image/xxx;base64, prefix in Base64 image data; pass only the encoded string itself.
- Mask images: The aspect ratio of a mask image must match the input
image; otherwise the task will fail.
- Video expiry: Generated video CDN links are automatically cleared after 30 days — download or transfer to Supabase Storage promptly.