curl https://api.apipod.ai/v1/videos/generations \
-H "Authorization: Bearer $APIPOD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}'import os
import requests
payload = {
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}
response = requests.post(
"https://api.apipod.ai/v1/videos/generations",
headers={
"Authorization": f"Bearer {os.environ['APIPOD_API_KEY']}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
response.raise_for_status()
print(response.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}`)
req, err := http.NewRequest(http.MethodPost, "https://api.apipod.ai/v1/videos/generations", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("APIPOD_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}use reqwest::Client;
use serde_json::json;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let payload = json!({
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
});
let response = Client::new()
.post("https://api.apipod.ai/v1/videos/generations")
.bearer_auth(env::var("APIPOD_API_KEY")?)
.json(&payload)
.send()
.await?
.error_for_status()?;
println!("{}", response.text().await?);
Ok(())
}const response = await fetch("https://api.apipod.ai/v1/videos/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.APIPOD_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}),
});
if (!response.ok) {
throw new Error(`APIPod request failed: ${response.status} ${await response.text()}`);
}
console.log(await response.json());{
"code": 200,
"message": "success",
"data": {
"task_id": "vid_task_01JEXAMPLE"
}
}Kling 3.0 Omni Image to Video
Kling 3.0 Omni I2V is APIPod’s first/last-frame image-to-video mode for Kling 3.0 Omni, the unified Kling 3.0 model with up to 4K output.
curl https://api.apipod.ai/v1/videos/generations \
-H "Authorization: Bearer $APIPOD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}'import os
import requests
payload = {
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}
response = requests.post(
"https://api.apipod.ai/v1/videos/generations",
headers={
"Authorization": f"Bearer {os.environ['APIPOD_API_KEY']}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
response.raise_for_status()
print(response.json())package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}`)
req, err := http.NewRequest(http.MethodPost, "https://api.apipod.ai/v1/videos/generations", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("APIPOD_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}use reqwest::Client;
use serde_json::json;
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let payload = json!({
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
});
let response = Client::new()
.post("https://api.apipod.ai/v1/videos/generations")
.bearer_auth(env::var("APIPOD_API_KEY")?)
.json(&payload)
.send()
.await?
.error_for_status()?;
println!("{}", response.text().await?);
Ok(())
}const response = await fetch("https://api.apipod.ai/v1/videos/generations", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.APIPOD_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"model": "kling-3.0-omni-i2v",
"prompt": "The flower bud in @image_1 slowly blooms into the open flower in @image_2, macro lens.",
"image_urls": [
"https://cdn.example.com/first-frame.jpg",
"https://cdn.example.com/last-frame.jpg"
],
"duration": 5,
"resolution": "1080p"
}),
});
if (!response.ok) {
throw new Error(`APIPod request failed: ${response.status} ${await response.text()}`);
}
console.log(await response.json());{
"code": 200,
"message": "success",
"data": {
"task_id": "vid_task_01JEXAMPLE"
}
}Usage notes
- First / last frame:
image_urls[0]is the first frame and the optionalimage_urls[1]is the last frame. The output aspect ratio follows the first frame. - Referencing inputs: images are numbered
image_1..image_Nin order and the video isvideo_1. Use@image_1/@video_1in the prompt to point at a specific input. - Multi-shot: set
multi_shottotruewithoutmulti_promptto let the model split the prompt into shots automatically, or describe up to 6 shots inmulti_prompt({prompt, duration}, up to 512 characters each) whose durations add up to exactlyduration. - Not supported:
negative_prompt(write exclusions into the prompt),audio_urls, andvideo_url(usevideo_urls).
Billing
Billed per second of output video. The per-second rate depends on the tier: 720p basic, 720p enhanced, 1080p basic, 1080p enhanced, or 4K. The enhanced tier applies when native audio is enabled or any video input is provided. Current prices are shown on the model page.Task flow
The create call returnsdata.task_id. Poll Query video task until status is completed (outputs in data.result) or failed, or pass callback_url to be notified when the task reaches a terminal state.Authorizations
Use your APIPod API key as a Bearer token in the Authorization header.
Body
Public APIPod model ID.
"kling-3.0-omni-i2v"First frame URL, optionally followed by a last frame URL (1-2 images). first_frame_image / last_frame_image are accepted as aliases. The aspect ratio follows the first frame.
1 - 2 elementsText prompt, up to 2,500 characters; required unless multi_prompt is provided. Inputs are numbered automatically: images become image_1..image_N in order and the video becomes video_1; reference them in the prompt as @image_1 or @video_1.
2500Output duration in seconds (3-15). Defaults to 5. With multi_prompt, the shot durations must add up to exactly this value; when omitted it defaults to the sum of the shot durations.
3 <= x <= 15Output resolution. Defaults to 720p. The per-second rate depends on the resolution tier.
720p, 1080p, 4k Generate native audio (alias audio). Defaults to false. Enabling it uses the enhanced billing tier.
Enable multi-shot generation (alias multi_shots). Without multi_prompt, the model splits the prompt into shots automatically.
Shot list for multi-shot generation, up to 6 shots. Each shot is {prompt, duration} with a prompt of up to 512 characters; the shot durations must add up to duration (3-15 seconds).
6Show child attributes
Show child attributes
When true, an additional watermarked copy is generated and the watermarked copy is returned as the result.
HTTPS URL that receives the task's terminal state.
Was this page helpful?