image_urlstringObligatoireImage de départ. Le clip démarre à partir de cette image et en reprend le format d’image.
- Valeur par défaut
- Non définie
- Contraintes
- format:"uri"contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
L’image-to-video Kling 3.0 part de votre image d’ouverture et rend 3 à 15 secondes en 720p, 1080p ou 4K. Ajoutez une image de clôture facultative, activez ou coupez l’audio natif, et choisissez un plan unique ou un montage multi-plans.
Les exemples suivent les paramètres publics du point de terminaison choisi. Remplacez la clé API et les médias d’exemple, puis envoyez la requête depuis votre serveur.
SDK et intégrationshttps://api.spicyapi.ai/api/v1/jobs/createTaskConservez la clé API dans la variable serveur SPICY_API_KEY. Utilisez l’authentification Bearer et Content-Type: application/json pour les requêtes 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"Généré à partir du schéma d’entrée de ce modèle, le même que l’API utilise pour valider chaque requête.
Placez ces champs dans l’objet input du corps de la requête. Les noms et types correspondent à l’API. Ne supposez aucune valeur par défaut si elle n’est pas indiquée.
Certains champs dépendent des autres entrées. Pour les champs obligatoires sous condition, consultez les règles complètes du JSON Schema ci-dessous.
image_urlstringObligatoireImage de départ. Le clip démarre à partir de cette image et en reprend le format d’image.
promptstringObligatoireDécrivez seulement ce qui se passe après l’image de départ — l’action, la caméra et, avec le son activé, le son.
guidance_scalenumberFacultatifDegré de fidélité du clip au prompt, de 0 à 1 (0,5 par défaut). Plus haut, il colle davantage au texte ; plus bas, il laisse plus de liberté au modèle. Sans effet sur le prix.
multi_promptarray<object>Obligatoire sous conditionLa liste de plans pour shot_type customize : jusqu’à 6 plans dans l’ordre, chacun avec son prompt (512 caractères au plus) et sa durée en secondes entières. Les durées doivent totaliser duration_seconds, qui reste la base de facturation.
multi_prompt[].duration_secondsintegerObligatoire dans l’objetLength of this shot in whole seconds, 1 to 15.
multi_prompt[].promptstringObligatoire dans l’objetWhat happens in this shot, up to 512 characters.
shot_typestringFacultatifsingle garde un seul dispositif la plupart du temps mais peut quand même couper de lui-même ; multi laisse Kling enchaîner ses propres coupes multi-plans. Ajoutez « un seul plan continu, sans coupe » pour une prise qui ne doit surtout pas être coupée. customize suit la liste de plans fournie dans multi_prompt.
"single""multi""customize"duration_secondsintegerFacultatifInflue sur le prixSecondes entières, de 3 à 15. Détermine le prix.
generate_audiobooleanFacultatifInflue sur le prixAjoute une bande sonore générée au même clip. En 720p et 1080p, cela coûte plus cher à la seconde qu’un rendu silencieux ; en 4K, le prix est le même avec ou sans son.
resolutionstringFacultatifInflue sur le prix720p, 1080p ou 4K. Les paliers supérieurs coûtent plus cher à la seconde.
"720p""1080p""4k"last_image_urlstringFacultatifImage de fin optionnelle. Sur les clips longs, le milieu peut dériver davantage que les extrémités ne restent fixes.
negative_promptstringFacultatifCe qui ne doit pas apparaître dans le clip (objets, rendus ou mouvements indésirables), jusqu’à 2 500 caractères. Facultatif ; sans effet sur le prix.
{
"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 signifie que la tâche est acceptée, pas terminée. Enregistrez le taskId renvoyé et interrogez cette tâche-là. N’en créez pas une seconde pendant l’attente.
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 réponse d’acceptation inclut l’estimation afin que votre application affiche le même montant dans l’historique des tâches et la facturation.
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
--data-urlencode "taskId=$TASK_ID" \
-H "Authorization: Bearer $SPICY_API_KEY"Commencez vers 2 secondes d’intervalle, puis espacez progressivement. Arrêtez-vous sur un état final. Après une coupure réseau, interrogez le taskId d’origine. Ne relancez la création qu’avec la clé d’idempotence et le corps d’origine.
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);
});Passez callBackUrl à la création de la tâche et l’enregistrement terminé vous est envoyé en POST — plus de boucle d’interrogation du tout. Chaque livraison porte X-Webhook-Timestamp, X-Webhook-Signature et X-Webhook-Payload-Version. La signature est un HMAC-SHA256 en base64 sur taskId.timestamp.sha256(body) : vérifiez-la donc sur les octets bruts, car analyser le JSON puis le re-sérialiser les modifie et le contrôle échouera. Les livraisons en échec sont réessayées, le même taskId peut donc arriver deux fois — rendez le gestionnaire idempotent. Répondez 2xx d’abord, traitez ensuite : un gestionnaire lent est compté comme une livraison ratée.
Ne traitez output que lorsque state vaut succeeded. En cas d’échec, consultez errorCode, errorMessage et request_id. Les coûts et états des exemples ne constituent pas une facture réelle.
{
"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"
}
}Pour chaque fichier disponible, ouvrez ou téléchargez assets[].url directement, sans en-tête Authorization. Le lien signé expire à expiresAt : relisez la tâche pour le renouveler tant que le fichier est dans sa période de conservation. Un fichier en attente ou indisponible n’a pas d’URL. Traitez les liens signés comme des données privées.
Utilisez SpicyAPI dans votre application, terminal, assistant IA ou workflow visuel. Choisissez un guide de configuration.
Autres intégrations
Rien ne vous oblige à écrire le code ci-dessus. Branchez le serveur MCP une fois et n’importe quel agent qui parle MCP — Claude Code, Codex, Cursor, Windsurf, VS Code, Gemini CLI, Cline, LibreChat — appelle ce modèle par son nom. Ou lancez-le depuis votre terminal en une commande.
Avec kling/3.0/image-to-video, anime ./poster.png — travelling avant lent, cinq secondes — et enregistre le clip à côté.
L’agent retrouve le modèle dans le catalogue, téléverse le fichier local à votre place, puis affiche le devis exact et son plafond de facturation et attend votre accord. Rien n’est facturé avant.
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 première ligne donne les outils à l’agent, la seconde lui donne le Skill — la règle du jeu qui va avec : chiffrer avant de facturer, téléverser les fichiers locaux au lieu d’en coller les octets, lire l’URL du résultat plutôt que la deviner. Les autres clients utilisent le même serveur via leur propre fichier de configuration : voir l’espace développeurs.
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"}' \
--waitL’entrée vient du schéma de ce point de terminaison, comme les exemples ci-dessus. --wait attend la fin de la tâche et l’affiche ; --yes évite la confirmation en intégration continue. Définissez d’abord SPICY_API_KEY — une seule clé pour l’API, la CLI et le serveur 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"}' \
--waitLa requête attend des URL, pas des octets. Téléversez d’abord le fichier et passez l’URI spicy:// renvoyée — le nom du champ ci-dessus vient du schéma de ce point de terminaison. Un agent connecté en MCP s’en charge tout seul, d’où la phrase plus haut qui désigne ./poster.png directement. Un média déjà accessible en HTTPS public n’a pas besoin d’être téléversé.
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 ne fait que raccourcir la durée — 30m, 1h, 7d, ou 0 pour supprimer dès que la tâche atteint un état final. La valeur réellement appliquée est la plus courte entre votre requête, vos réglages de compte et le plafond de la plateforme : relisez-la dans l’enregistrement de la tâche au lieu de supposer que votre valeur est passée. Demander plus long que ce qu’autorise le compte ne fait rien.
Installez les nœuds SpicyAPI depuis ComfyUI Manager ou avec la commande ci-dessous, puis cherchez Kling 3.0 · Image to Video sur le canevas. Le nœud propose les mêmes options que cette page et affiche son prix avant de s’exécuter.
cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapiLe panneau intégré lit le même schéma que cette page : il ne peut donc pas diverger de l’API. Si votre documentation a besoin d’un contenu indexable, récupérez plutôt le JSON sous /api/embed/models/ et affichez-le vous-même.
<iframe src="https://spicyapi.ai/embed/fr/models/kling-3-0/api?model=kling%2F3.0%2Fimage-to-video" width="100%" height="560" loading="lazy" title="Exemple de requête" style="border:1px solid rgba(0,0,0,.12)"></iframe>