image_urlstringОбязательноПервый кадр. Клип начинается с этого изображения и берёт от него соотношение сторон.
- По умолчанию
- Не задано
- Ограничения
- format:"uri"contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
Kling 3.0 image-to-video стартует с вашего первого кадра и рендерит 3–15 секунд в 720p, 1080p или 4K. Добавьте необязательный финальный кадр, включите или выключите нативный звук, выберите один план или монтаж.
Примеры используют публичные параметры выбранного эндпоинта. Замените API-ключ и примеры медиафайлов, затем отправьте запрос со своего сервера.
SDK и интеграцииhttps://api.spicyapi.ai/api/v1/jobs/createTaskХраните API-ключ в серверной переменной окружения SPICY_API_KEY. Используйте Bearer-аутентификацию и Content-Type: application/json для JSON-запросов.
Authorization: Bearer $SPICY_API_KEY# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
-d '{
"model": "kling/3.0/image-to-video",
"input": {
"duration_seconds": 5,
"generate_audio": false,
"image_url": "https://example.com/reference.png",
"prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
"resolution": "720p",
"shot_type": "single"
}
}'
# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"Пример построен по входной схеме этой модели — той же, по которой API проверяет каждый запрос.
Поместите эти поля в объект input тела запроса. Имена и типы соответствуют API. Не предполагайте значение по умолчанию, если оно не задано.
Некоторые поля зависят от других входных данных. Полные правила для условно обязательных полей приведены в JSON Schema ниже.
image_urlstringОбязательноПервый кадр. Клип начинается с этого изображения и берёт от него соотношение сторон.
promptstringОбязательноОпишите только то, что происходит после первого кадра — действие, камеру и, при включённом звуке, звук.
guidance_scalenumberНеобязательноНасколько точно ролик следует промпту, от 0 до 1 (по умолчанию 0,5). Чем выше, тем ближе к тексту; чем ниже, тем больше свободы у модели. На цену не влияет.
multi_promptarray<object>Обязательно при условииСписок планов для shot_type customize: до 6 планов по порядку, у каждого свой промпт (до 512 символов) и длина в целых секундах. Сумма длин должна совпадать с duration_seconds, по которому по-прежнему идёт оплата.
multi_prompt[].duration_secondsintegerОбязательно внутри объектаLength of this shot in whole seconds, 1 to 15.
multi_prompt[].promptstringОбязательно внутри объектаWhat happens in this shot, up to 512 characters.
shot_typestringНеобязательноsingle удерживает одну установку камеры в основном ходе, но всё же может сделать склейку сама; multi позволяет Kling самой смонтировать несколько планов. Добавьте «один непрерывный план, без склеек» в промпт для дубля, который не должен прерываться. customize следует списку планов из multi_prompt.
"single""multi""customize"duration_secondsintegerНеобязательноВлияет на ценуЦелые секунды, от 3 до 15. Влияет на цену.
generate_audiobooleanНеобязательноВлияет на ценуДобавляет сгенерированную звуковую дорожку к тому же клипу. В 720p и 1080p это дороже за секунду, чем без звука; в 4K цена одинакова со звуком и без.
resolutionstringНеобязательноВлияет на цену720p, 1080p или 4K. Более высокие уровни стоят дороже за секунду.
"720p""1080p""4k"last_image_urlstringНеобязательноНеобязательный последний кадр. На длинных клипах середина может «плыть» сильнее, чем удерживаются края.
negative_promptstringНеобязательноТо, чего не должно быть в ролике, — объекты, стилистика или движения, до 2500 символов. Необязательно; на цену не влияет.
{
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"shot_type": {
"const": "customize"
}
},
"required": [
"shot_type"
]
},
"then": {
"required": [
"multi_prompt"
]
}
}
],
"properties": {
"duration_seconds": {
"default": 5,
"description": "Output length in whole seconds, from 3 to 15. Billed per second.",
"maximum": 15,
"minimum": 3,
"type": "integer",
"x-ui": {
"affects_price": true,
"order": 60,
"step": 1,
"unit": "s",
"widget": "slider"
}
},
"generate_audio": {
"default": false,
"description": "Generate a native soundtrack (voices, effects, ambience) with the picture. Audio costs more per second.",
"type": "boolean",
"x-ui": {
"affects_price": true,
"order": 65,
"widget": "switch"
}
},
"guidance_scale": {
"default": 0.5,
"description": "How closely the clip follows the prompt, from 0 to 1. Higher sticks to the prompt more; lower gives the model more freedom.",
"maximum": 1,
"minimum": 0,
"type": "number",
"x-ui": {
"advanced": true,
"order": 20,
"step": 0.01,
"widget": "slider"
}
},
"image_url": {
"contentMediaType": [
"image/jpeg",
"image/png",
"image/webp",
"image/gif"
],
"description": "Opening frame. The clip starts from this image.",
"format": "uri",
"type": "string",
"x-ui": {
"max_size_mb": 10,
"order": 90,
"widget": "upload"
}
},
"last_image_url": {
"contentMediaType": [
"image/jpeg",
"image/png",
"image/webp",
"image/gif"
],
"description": "Optional closing frame the clip should end on.",
"format": "uri",
"type": "string",
"x-ui": {
"max_size_mb": 10,
"order": 85,
"widget": "upload"
}
},
"multi_prompt": {
"description": "Shot list for shot_type customize: one entry per shot, in order, each with its own prompt and length in seconds. The lengths must add up to duration_seconds.",
"items": {
"additionalProperties": false,
"properties": {
"duration_seconds": {
"description": "Length of this shot in whole seconds, 1 to 15.",
"maximum": 15,
"minimum": 1,
"type": "integer"
},
"prompt": {
"description": "What happens in this shot, up to 512 characters.",
"maxLength": 512,
"minLength": 1,
"type": "string"
}
},
"required": [
"prompt",
"duration_seconds"
],
"type": "object"
},
"maxItems": 6,
"minItems": 1,
"type": "array",
"x-ui": {
"order": 54,
"widget": "object-list"
}
},
"negative_prompt": {
"description": "What to keep out of the clip: objects, looks or motion you do not want.",
"maxLength": 2500,
"type": "string",
"x-ui": {
"order": 95,
"widget": "textarea"
}
},
"prompt": {
"description": "Describe what happens after the opening frame: the action, the camera and, with sound on, the sounds.",
"maxLength": 2500,
"minLength": 1,
"type": "string",
"x-ui": {
"order": 100,
"primary": true,
"widget": "textarea"
}
},
"resolution": {
"default": "720p",
"description": "Output resolution. Higher tiers cost more per second.",
"enum": [
"720p",
"1080p",
"4k"
],
"type": "string",
"x-ui": {
"affects_price": true,
"order": 70,
"widget": "radio"
}
},
"shot_type": {
"default": "single",
"description": "single keeps one continuous shot; multi lets the model cut the prompt into several shots on its own; customize follows the shot list you give in multi_prompt.",
"enum": [
"single",
"multi",
"customize"
],
"type": "string",
"x-ui": {
"order": 55,
"widget": "radio"
}
}
},
"required": [
"prompt",
"image_url"
],
"type": "object",
"x-pricing": {
"billingMode": "variant_matrix",
"variantFields": [
"resolution",
"generate_audio"
]
}
}HTTP 202 означает принятие задачи, а не завершение генерации. Сохраните полученный taskId и проверяйте эту задачу. Не создавайте новую, пока ждёте результат.
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3
{
"code": 200,
"msg": "success",
"request_id": "req_example_create",
"data": {
"taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
"state": "queued",
"estimatedCost": "0.750000"
}
}В ответе о приёме есть оценка стоимости — приложение сможет показать ту же сумму в истории задач и в расчётах.
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
--data-urlencode "taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"Начните с интервала около 2 секунд и постепенно увеличивайте его. Прекратите опрос при конечном состоянии. После сбоя соединения используйте исходный taskId. Повторно создавать задачу можно только с исходным ключом идемпотентности и исходным телом запроса.
import { verifyWebhook } from "@spicyapi/sdk";
// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
const { payload } = verifyWebhook({
rawBody: req.body,
timestamp: req.header("X-Webhook-Timestamp"),
signature: req.header("X-Webhook-Signature"),
payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
secret: process.env.SPICY_WEBHOOK_SECRET,
});
res.status(200).end();
void handleFinishedTask(payload);
});Передайте callBackUrl при создании задачи — готовая запись придёт к вам POST-запросом, и никакого опроса не понадобится. В каждой доставке есть X-Webhook-Timestamp, X-Webhook-Signature и X-Webhook-Payload-Version. Подпись — это HMAC-SHA256 в base64 от taskId.timestamp.sha256(body), поэтому проверять её нужно по исходным байтам: если разобрать JSON и сериализовать заново, байты изменятся и проверка не пройдёт. Неудачные доставки повторяются, так что один и тот же taskId может прийти дважды — сделайте обработчик идемпотентным. Сначала ответьте 2xx, работу выполняйте после: медленный обработчик считается неудачной доставкой.
Обрабатывайте output только при state, равном succeeded. При ошибке проверьте errorCode, errorMessage и request_id. Стоимость и состояния в примерах не являются фактическим счётом.
{
"code": 200,
"msg": "success",
"request_id": "req_example_record",
"data": {
"taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
"model": "kling/3.0/image-to-video",
"state": "succeeded",
"output": {
"assets": [
{
"key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/3f7a1c9e5b2d48f0a6c1e3d5b7f9a1c3.mp4",
"mime": "video/mp4",
"url": "https://example.r2.cloudflarestorage.com/results/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
"expiresAt": "2026-08-28T12:20:08.000Z"
}
]
},
"cost": "0.750000",
"settled": true,
"createdAt": "2026-08-28T12:00:00Z",
"completedAt": "2026-08-28T12:00:30Z"
}
}Доступные файлы можно открыть или скачать по assets[].url без заголовка API Authorization. Подписанная ссылка действует до expiresAt. Чтобы обновить её, повторно запросите задачу в течение срока хранения файла. У ожидающих или недоступных файлов URL отсутствует. Не передавайте подписанные ссылки посторонним.
Используйте SpicyAPI в приложении, терминале, ИИ-ассистенте или визуальном процессе. Выберите руководство по настройке.
Писать код выше вовсе не обязательно. Подключите сервер MCP один раз — и любой агент, который говорит на MCP (Claude Code, Codex, Cursor, Windsurf, VS Code, Gemini CLI, Cline, LibreChat), вызовет эту модель по имени. Либо запустите её из терминала одной командой.
Возьми kling/3.0/image-to-video и оживи ./poster.png — медленный наезд, пять секунд — и положи клип рядом.
Агент найдёт модель в каталоге, сам загрузит локальный файл, покажет точную смету и предельную сумму списания — и дождётся вашего согласия. До этого ничего не списывается.
claude mcp add spicyapi -e SPICY_API_KEY=$SPICY_API_KEY \
-- npx --yes --package=@spicyapi/mcp spicyapi-mcp
npx skills add spicyapi-ai/spicy-skillПервая строка даёт агенту инструменты, вторая — Skill, то есть правила обращения с ними: сначала смета, потом списание; локальные файлы загружать, а не вставлять байтами; URL готового результата читать, а не угадывать. Остальные клиенты подключают тот же сервер через собственный файл настроек — см. раздел для разработчиков.
npx @spicyapi/cli tasks create --model kling/3.0/image-to-video \
--input-json '{"duration_seconds":5,"generate_audio":false,"image_url":"https://example.com/reference.png","prompt":"A slow aerial shot drifting over a misty pine forest at sunrise","resolution":"720p","shot_type":"single"}' \
--waitВходные данные взяты из схемы этого эндпоинта — той же, что и в примерах выше. --wait дождётся завершения задачи и выведет её, а --yes пропустит подтверждение в CI. Сначала задайте SPICY_API_KEY: один ключ работает и для API, и для CLI, и для сервера MCP.
npx @spicyapi/cli files upload ./poster.png
# -> spicy://uploads/01k3m8x9q2z4v7n5p6r8s0t1w3
npx @spicyapi/cli tasks create --model kling/3.0/image-to-video \
--input-json '{"image_url":"spicy://uploads/01k3m8x9q2z4v7n5p6r8s0t1w3"}' \
--waitВ запрос попадают URL, а не байты. Сначала загрузите файл и подставьте выданный spicy:// URI — имя поля выше взято из схемы этого эндпоинта. Агент через MCP делает это сам, потому фраза выше и может прямо назвать ./poster.png. Медиа, уже доступное по публичному HTTPS, загружать не нужно.
npx @spicyapi/cli tasks create --model kling/3.0/image-to-video \
--input-json '{…}' --retention 1h --wait
npx @spicyapi/cli tasks get $TASK_ID # read back the retention that appliedКлюч --retention только сокращает срок — 30m, 1h, 7d или 0, чтобы удалить сразу после перехода задачи в конечное состояние. Реально действует наименьшее из трёх: ваш запрос, настройки аккаунта и предел платформы, — поэтому считайте его из записи задачи, а не исходите из того, что запрошенное число применилось. Запросить срок больше разрешённого аккаунтом нельзя: это ничего не изменит.
Установите узлы SpicyAPI через ComfyUI Manager или командой ниже и найдите на холсте Kling 3.0 · Image to Video. У узла те же параметры, что и на этой странице, а цена показывается до запуска.
cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapiВстроенная панель читает ту же схему, что и эта страница, поэтому не может разойтись с API. Если содержимое должно индексироваться поиском по документации, возьмите JSON из /api/embed/models/ и отрисуйте его самостоятельно.
<iframe src="https://spicyapi.ai/embed/ru/models/kling-3-0/api?model=kling%2F3.0%2Fimage-to-video" width="100%" height="560" loading="lazy" title="Пример запроса" style="border:1px solid rgba(0,0,0,.12)"></iframe>