image_urlstringObligatorioCuadro inicial. El clip parte de esta imagen y toma su relación de aspecto de ella.
- Valor predeterminado
- Sin especificar
- Restricciones
- format:"uri"contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
El image-to-video de Kling 3.0 parte de tu cuadro de apertura y renderiza de 3 a 15 segundos a 720p, 1080p o 4K. Añade un cuadro de cierre opcional, activa o desactiva el audio nativo y elige una sola toma o un montaje de varios planos.
Los ejemplos usan las definiciones públicas de parámetros del endpoint seleccionado. Sustituye la clave de API y los medios de ejemplo, y envía la solicitud desde tu servidor.
SDK e integracioneshttps://api.spicyapi.ai/api/v1/jobs/createTaskGuarda la clave de API en la variable de entorno del servidor SPICY_API_KEY. Usa autenticación Bearer y Content-Type: application/json en las solicitudes 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"Generado a partir del esquema de entrada de este modelo: el mismo con el que la API valida cada solicitud.
Incluye estos campos en el objeto input del cuerpo de la solicitud. Los nombres y tipos coinciden con la API. No supongas un valor predeterminado si no está indicado.
Este modelo tiene dependencias entre campos. Los marcados como obligatorios según condición dependen de otras entradas; abajo, en el JSON Schema completo, están las reglas.
image_urlstringObligatorioCuadro inicial. El clip parte de esta imagen y toma su relación de aspecto de ella.
promptstringObligatorioDescribe solo lo que pasa después del cuadro inicial: la acción, la cámara y, con el sonido activado, el sonido.
guidance_scalenumberOpcionalQué tan fiel es el clip al prompt, de 0 a 1 (por defecto 0.5). Un valor más alto se ciñe más al texto; uno más bajo le da más libertad al modelo. No cambia el costo.
multi_promptarray<object>Obligatorio según condiciónLa lista de tomas para shot_type customize: hasta 6 tomas en orden, cada una con su propio prompt (hasta 512 caracteres) y su duración en segundos enteros. Las duraciones deben sumar duration_seconds, que sigue siendo lo que se cobra.
multi_prompt[].duration_secondsintegerObligatorio dentro del objetoLength of this shot in whole seconds, 1 to 15.
multi_prompt[].promptstringObligatorio dentro del objetoWhat happens in this shot, up to 512 characters.
shot_typestringOpcionalsingle mantiene una sola configuración la mayor parte de la corrida pero aun así puede cortar por su cuenta; multi deja que Kling haga su propio montaje de varios planos. Agrega "one continuous shot, no cuts" en el prompt para una toma que no deba cortarse. customize sigue la lista de tomas que das en multi_prompt.
"single""multi""customize"duration_secondsintegerOpcionalAfecta al precioSegundos completos, de 3 a 15. Determina el precio.
generate_audiobooleanOpcionalAfecta al precioAgrega una banda sonora generada al mismo clip. En 720p y 1080p cuesta más por segundo que una corrida silenciosa; en 4K el precio es el mismo con o sin sonido.
resolutionstringOpcionalAfecta al precio720p, 1080p o 4K. Los niveles más altos cuestan más por segundo.
"720p""1080p""4k"last_image_urlstringOpcionalCuadro final opcional. En clips largos, el medio puede desviarse más de lo que los extremos se mantienen fijos.
negative_promptstringOpcionalLo que no quieres en el clip (objetos, estilos o movimientos), hasta 2500 caracteres. Opcional; no cambia el costo.
{
"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 significa que la tarea se aceptó, no que haya terminado. Guarda el taskId devuelto y consulta esa tarea. No crees otra mientras esperas el resultado.
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"
}
}La respuesta de aceptación incluye la estimación para que tu aplicación pueda mostrar el mismo importe en el historial de tareas y en la facturación.
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
--data-urlencode "taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"Empieza consultando cada 2 segundos aproximadamente y ve espaciando los intentos. Párate en un estado final. Si se cae la conexión, consulta el taskId original. Vuelve a crear la tarea solo con la clave de idempotencia y el cuerpo originales.
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);
});Pasa callBackUrl al crear la tarea y recibirás el registro terminado por POST, sin un bucle de consultas de estado. Cada entrega lleva X-Webhook-Timestamp, X-Webhook-Signature y X-Webhook-Payload-Version. La firma es un HMAC-SHA256 en base64 sobre taskId.timestamp.sha256(body), así que debes verificarla con los bytes originales: si analizas el JSON y vuelves a serializarlo, los bytes cambian y la verificación falla. Las entregas fallidas se reintentan, de modo que el mismo taskId puede llegar dos veces; haz que tu manejador sea idempotente. Responde 2xx primero y haz el trabajo después: un manejador lento se trata como una entrega fallida.
Procesa output solo cuando state sea succeeded. Si falla, consulta errorCode, errorMessage y request_id. Los costos y estados de ejemplo no representan una factura real.
{
"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"
}
}Para cada archivo disponible, abre o descarga assets[].url directamente, sin la cabecera Authorization de la API. El enlace firmado expira en expiresAt: vuelve a consultar la tarea para renovarlo mientras el archivo siga dentro del periodo de conservación. Un archivo pendiente o no disponible no trae URL. Trata los enlaces firmados como datos privados.
Usa SpicyAPI en tu app, terminal, asistente de IA o flujo visual. Elige una guía de configuración.
No hace falta que escribas nada del código anterior. Conecta el servidor MCP una vez y cualquier agente que use MCP — Claude Code, Codex, Cursor, Windsurf, VS Code, Gemini CLI, Cline, LibreChat — podrá ejecutar este modelo por su nombre. También puedes ejecutarlo desde tu terminal con un solo comando.
Use kling/3.0/image-to-video to animate ./poster.png — slow push-in, five seconds — and save the clip next to it.
El agente busca el modelo en el catálogo actualizado, sube el archivo local por ti, te muestra la cotización exacta y el cargo máximo, y espera tu confirmación. No se cobra nada hasta que aceptes.
claude mcp add spicyapi -e SPICY_API_KEY=$SPICY_API_KEY \
-- npx --yes --package=@spicyapi/mcp spicyapi-mcp
npx skills add spicyapi-ai/spicy-skillLa primera línea le da las herramientas al agente; la segunda le da el Skill, las reglas para usarlas: consultar la cotización antes de cobrar, subir los archivos locales en lugar de pegar sus bytes y leer la URL del resultado en vez de adivinarla. Los demás clientes usan el mismo servidor desde su propio archivo de configuración: consulta el área de desarrolladores.
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"}' \
--waitLa entrada usa el esquema de este endpoint, igual que los ejemplos de arriba. --wait consulta el estado hasta que la tarea termina y lo imprime; agrega --yes para omitir la confirmación en CI. Define antes SPICY_API_KEY: una misma clave sirve para la API, la CLI y el servidor 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"}' \
--waitEl cuerpo de la solicitud admite URL, no bytes. Sube primero el archivo y pasa el URI spicy:// que devuelve; el nombre del campo de arriba sale del esquema de este endpoint. Un agente conectado por MCP hace ese paso por ti, y por eso la frase anterior puede nombrar ./poster.png directamente. Los archivos ya accesibles por HTTPS público no necesitan subirse.
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 solo acorta el plazo: 30m, 1h, 7d, o 0 para borrar en cuanto la tarea llega a un estado final. Se aplica el plazo más corto entre tu solicitud, los ajustes de tu cuenta y el máximo de la plataforma. Consúltalo en el registro de la tarea en vez de asumir que se aplicó el plazo que pediste. Pedir más tiempo del que permite tu cuenta no tiene efecto.
Instala los nodos de SpicyAPI desde ComfyUI Manager o con el comando de abajo y busca Kling 3.0 · Image to Video en el lienzo. El nodo tiene las mismas opciones que esta página y muestra su precio antes de ejecutarse.
cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapiEl panel incrustado lee el mismo esquema que esta página, así que no puede desincronizarse de la API. Si tu documentación necesita contenido indexable, toma el JSON de /api/embed/models/ y renderízalo tú mismo.
<iframe src="https://spicyapi.ai/embed/es/models/kling-3-0/api?model=kling%2F3.0%2Fimage-to-video" width="100%" height="560" loading="lazy" title="Ejemplo de solicitud" style="border:1px solid rgba(0,0,0,.12)"></iframe>