Video-to-Video
Restyle and transform existing videos using AI with the Kolbo API.
Restyle and transform existing videos using AI. Provide a source video and a text prompt describing the desired transformation, and Kolbo generates a new video with the applied style or changes.
model is required here. Unlike the other generation endpoints, video-to-video does not support Smart Select — the model families are too heterogeneous (restyle vs. subtitles vs. motion control) for an auto-pick. Omitting model (or sending an auto-select alias such as "auto" / "smart-select" / "") returns 400 with code MODEL_REQUIRED. List the options with GET /api/v1/models?type=video_from_video (or the canonical ?type=video_to_video — both return the same models) and pass an identifier.
Model identifiers are Kolbo-specific. Never hardcode model identifiers — always fetch the current list from GET /api/v1/models?type=video_from_video first. Models may be added, renamed, or retired at any time. model must be a string; an array or object returns 400 with code INVALID_MODEL.
All generation endpoints accept an optional
project_idbody field that routes the output into a specific project. See Projects. Rate limit: 30 accepted requests per minute per user (all API keys on one account share the counter), counted in one bucket shared with the other standard-limit/v1/generate/*routes; requests that fail are not counted. The endpoint returns403/INSUFFICIENT_CREDITSbefore any work starts when the account cannot cover the generation.
Endpoint
POST /api/v1/generate/video-from-videoRequest Body
Accepts multipart/form-data (for file uploads) or application/json (for URL-based inputs).
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model identifier from GET /api/v1/models?type=video_from_video. The identifier's types array must contain video_to_video — anything else (an image-to-video model, for example) is rejected up front with 400 and code WRONG_MODEL_TYPE; the error string names each rejected identifier and its real types. No auto-select — see the callout above. |
video_url | string | Conditional | URL of the primary input video. Required unless you upload a files part. Must be a Kolbo-hosted URL (upload through the Media Library first, or reuse a Kolbo output URL) — any other host returns 400 / INVALID_VIDEO_SOURCE (Use a video uploaded to your Kolbo media library.). For motion-control models this slot carries the driving video — see Motion Control. |
files | file(s) | Conditional | Video file upload (multipart field name files, max 100 MB per file). Required unless video_url is set. |
prompt | string | No | Describe the desired transformation or style. Optional at the API layer, but effectively required by most models: everything outside the prompt-less families fails with 400 Missing required field: prompt in metadata. Prompt-less: VEED Subtitles, Act Two, Wan Animate, Kling Motion Control, Bytedance Dreamactor, prunaai/p-video-animate / prunaai/p-video-replace, the Seedance extend models, the Morphious (kolbo-morphious-*) family (falls back to a built-in instruction for the mode; prompt capped at 4000 characters) and the Genjutsu (higgsfield-genjutsu-*) family (sent as-is, empty allowed; capped at 10,000 characters) — an over-long prompt on either returns 400 / INVALID_MORPHIOUS_INPUT, and every ltx-2.3-quality/… variant other than reference-video-to-video and inpaint. When present it must be a string, otherwise 400 / INVALID_PROMPT. |
aspect_ratio | string | No | Output aspect ratio. Must be one of the model's supported_aspect_ratios. Default: "16:9" — except Seedance models (seedance…), which keep the source video's shape (adaptive) when you omit it, and kolbo-morphious-reframe, which has no default and rejects a request without a target ratio (Choose a target aspect ratio for Reframe). |
duration | number | string | No | Output duration in seconds. Must be in supported_durations, or within min_output_duration–max_output_duration. Omit and the fallback is model-dependent — most models match the source length, others apply their own default. Billing is usually based on the probed source length, not this value — see Billing. |
enhance_prompt | boolean | No | Run the prompt through Kolbo's enhancer. Default: false. true enables it; in a multipart/form-data request send the string "true" (or "1"). Always off for Morphious and Genjutsu models. |
resolution | string | No | Video resolution tier (e.g. "720p", "1080p"). Model-dependent — check supported_resolutions on GET /api/v1/models?type=video_from_video. Higher tiers may multiply the credit cost — see Credit Multipliers. "480p-draft" selects Draft on models that list it (see draft). |
draft | boolean | No | Draft mode (true / false, or the strings "true" / "false"). true forces the model's 480p Draft tier regardless of resolution; only models whose supported_resolutions include 480p-draft (currently the Seedance 2.5 video-to-video and extend models) support it — any other model returns 400 / UNSUPPORTED_DRAFT_MODE. A non-boolean value returns 400 / INVALID_DRAFT_MODE. |
sound_enabled | boolean | No | Billing only on this endpoint. It is recorded on the generation and fed to the credit calculation (the model's sound_credit_multiplier), but video-to-video never translates it into a provider sound parameter — it cannot turn audio on or off in the output. Leave it unset unless you know why you are sending it. |
visual_dna_ids | array of strings | No | Visual DNA profile IDs (a single ID string, or a JSON-encoded array in multipart, is also accepted). You can instead tag a DNA by name in the prompt (@Name) — mentions are resolved only when no IDs are sent. On models that take reference images, the DNA stills are appended after your own reference_images and the @Name in the dispatched prompt is rewritten to the matching image slot; Kling O1/O3 consume DNA through their elements path. On a model with no image slots the @Name is reduced to plain text. An unknown or inaccessible DNA is skipped without failing the request — except on Morphious / Genjutsu models, which validate the selection and return 400 / INVALID_MORPHIOUS_DNA (or INVALID_GENJUTSU_DNA). |
reference_images | array of strings | No | Reference image URLs for models that take image inputs. A single URL string is also accepted; entries that are not http(s) URLs are dropped and duplicates removed. Pass at most max_images from the model record — max_images: 0 means the model takes none. There is no generic server-side cap check (see Input limits), so over-sending usually fails at the provider instead of returning a clean 400. Required for motion-control models and for prunaai/p-video-animate / prunaai/p-video-replace — see Motion Control. |
reference_videos | array of strings | No | Additional reference video URLs. On Seedance models (seedance…) they are sent as extra video inputs after the source video (each one is admitted and billed as video input). On every other model they land in the slot the legacy WAN 2.6 reference-to-video models read as videos; the other provider paths that read that slot (Yike, Pruna P-Video) merge it into their reference-image list, so there these URLs are sent as images, not videos. Morphious and Genjutsu models reject it with 400 (… takes exactly one source video (video_url); reference_videos is not supported.). |
elements | array of strings | No | Element image URLs (style / character reference assets alongside the main video), consumed by the Kling O1/O3 video-to-video edit models. Pass at most max_elements from the model record; max_elements: 0 means the model takes none. Not enforced server-side. |
keyframes | array of objects | No | Timestamp-anchored keyframes, each { "image_url": string, "timestamp_seconds": number } (camelCase imageUrl / timestampSeconds are accepted too). Only accepted by models that declare keyframe support — on any other model they are silently dropped and a plain video-to-video runs instead. Any entry whose image_url is missing or whose timestamp_seconds is not a finite number is dropped without an error before validation, so malformed entries shrink the array rather than failing the request. Surviving entries: images must be Kolbo-hosted (upload via Media Library first) — an external URL returns 400 Keyframe images must be uploaded to Kolbo first.; a negative timestamp returns 400 Each keyframe requires a valid timestamp (seconds ≥ 0).; a timestamp more than 1 s past source_duration_seconds returns 400 Keyframe timestamp is beyond the video duration., a smaller overshoot is clamped to the duration, and two keyframes on the same timestamp (to the millisecond) are separated by nudging the later one down in 0.1 s steps (a duplicate that cannot be separated is dropped). More surviving entries than the model's keyframe ceiling returns 400 This model accepts at most N keyframes. Accepted keyframes are reduced to image_url + timestamp_seconds and re-sorted ascending by time, so the order you send them in does not matter. |
source_fps | number | No | Frame rate of the source video. Only read alongside keyframes, to place them accurately. |
source_duration_seconds | number | No | Duration of the source video in seconds. Only read alongside keyframes — it is the ceiling that keyframe timestamps are validated against. Omit it (or send a non-positive value) and no ceiling check runs at all. |
preset | string | No | VEED Subtitles: caption style preset (e.g. "glass", "whisper", "fusion", "simple", "vegas"). Preset-backed models (such as kolbo_relight): the id of one of the model's looks; omitted or unknown, the model's default look is used. Ignored by other models. |
source_language | string | No | VEED Subtitles only. BCP-47 code of the spoken language to improve transcription accuracy (e.g. "en-US", "es-ES", "he-IL"). Omit to auto-detect. |
translation_language | string | No | VEED Subtitles only. BCP-47 code to translate the subtitles into (e.g. "en-US", "fr-FR"). Omit to keep the original spoken language. |
srt_content | string | No | VEED Subtitles only. Raw .srt subtitle text to burn in. When set, auto-transcription is skipped. |
srt_file_url | string | No | VEED Subtitles only. URL to a .srt file. Alternative to srt_content. When set, auto-transcription is skipped. |
vocabulary | array | No | VEED Subtitles only. Brand names / jargon to help transcription, e.g. [{"word":"Kolbo","replaces":["colbo"]}]. Ignored when srt_content / srt_file_url is set. |
customization | object | No | VEED Subtitles only. Style overrides — position (top/center/bottom), shadow (none/min/mid/max), and text_customizations.baseline / .highlighted each with font (Google font name), weight (100-900), color (hex). Any omitted field keeps the preset default; best supported by Basic presets. |
style_id | string | No | Morphious Standard only (kolbo-morphious-motion / kolbo-morphious-swap). A style id from GET /api/v1/morphious-styles (catalog or one of your own; see Morphious Styles). The style takes 5 of the model's reference-image slots, so fewer of your own reference_images fit. The Lite modes and Reframe reject a style. |
render_mode | string | No | Morphious only. "motion" or "swap" — forces the render route. Any other value is ignored. |
reference_map | object | No | Morphious only. Where each trend reference lands. Accepted only as a plain object (JSON body) whose JSON is at most 4000 characters; anything else is silently dropped. |
enhancement_model | string | No | Topaz Slow Motion only (topaz/interpolate/video): retiming engine — "Apollo", "Chronos" or "Aion". Aion is billed at its own, higher rate class. |
target_fps | number | No | Topaz Slow Motion only. Output frame rate, clamped to 16–120. Rates above 60 raise the billed length proportionally. |
slowdown_factor | number | No | Topaz Slow Motion only. How many times longer the output runs, 1–8. Billing is on the output length, so 8x costs 8x. |
output_format | string | No | Topaz SDR-to-HDR only (topaz/sdr-to-hdr/video): "mp4" (10-bit H.265 HDR10, default) or "prores" (10-bit ProRes 422 HQ). |
project_id | string | No | Project to file the generation into. See Projects. |
session_id | string | No | An existing video-to-video session you own to append this generation to. Omit and Kolbo picks the API session for the project. |
You must provide video_url or a files upload. With neither, the request fails with 400 Provide video_url or upload a video file — this gate is unconditional, including for the model families that could otherwise run from reference inputs alone. Sending both is not rejected: the uploaded file wins and video_url is ignored.
Array and object fields (reference_images, reference_videos, elements, keyframes, vocabulary, customization, visual_dna_ids) may be sent as real JSON in a JSON body, or as JSON-encoded strings in a multipart/form-data request. A value that does not parse to a non-empty array/object is dropped silently. reference_map is only read from a JSON body.
Errors from the generation pipeline (prompt, keyframe and model-family validation) come back as { "success": false, "error": "…", "code": "…" }. When the pipeline sets no code of its own, code is GENERATION_ERROR — match on the HTTP status and the error text in that case.
The LTX inpaint variant cannot be driven from this endpoint. ltx-2.3-quality/inpaint requires a tracked mask video, and there is no request field to supply one — every call fails with 400 Inpaint requires a mask. Draw a box over the object first. Use one of the other video_to_video models, or the inpaint operation on POST /api/v1/edit/video, which does take a mask_video_url.
Motion Control (character image + driving video)
Motion-control models transfer the motion of a reference video onto a character image. They are matched by identifier: anything containing motion-control (such as the Kling v2.6 / v3 motion-control models), animate-move / animate/move (including wan/v2.2-14b/animate/move), wan-animate or dreamactor (including bytedance/dreamactor/v2), plus act_two. For these models the inputs are:
reference_images[0]— the character image (the subject that gets animated). Must be a Kolbo-hosted URL whose path has an image extension (.jpg,.jpeg,.png,.gif,.bmp,.webp,.tiff), otherwise400withINVALID_VIDEO_SOURCEorINVALID_CHARACTER_IMAGE_TYPE.video_url— the driving / reference video whose motion is transferred (in the MCP tool this is thesource_videoargument). Its path must have a video extension (.mp4,.mov,.avi,.mkv,.webm,.m4v,.flv,.wmv), otherwise400/INVALID_REFERENCE_VIDEO_TYPE.
Omitting the character image, or sending the driving video as an uploaded files part instead of video_url, returns 400 with code MOTION_CONTROL_INPUTS before any credits are held. Send both as URLs (upload a local file to the Media Library first). The cost is sized from the driving video's length.
wan/v2.2-14b/animate/replace is not a motion-control model: it keeps the scene video in video_url and takes the character image as reference_images[0] (400 / MOTION_CONTROL_INPUTS when it is missing). prunaai/p-video-animate and prunaai/p-video-replace work the normal way: source video in video_url plus at least one reference_images entry (400 / MISSING_REFERENCE_IMAGE otherwise, TOO_MANY_REFERENCE_IMAGES above the model's cap).
curl -X POST https://api.kolbo.ai/api/v1/generate/video-from-video \
-H "X-API-Key: kolbo_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-motion-control-model-identifier",
"reference_images": ["https://media.kolbo.ai/images/character.jpg"],
"video_url": "https://media.kolbo.ai/videos/dance-reference.mp4"
}'VEED Subtitles (prompt-less)
The VEED Subtitles model (veed/subtitles) burns styled, auto-transcribed subtitles into a video. It takes no prompt — pass a style preset and optional language settings instead. Billed per minute of input video with a 1-minute minimum.
curl -X POST https://api.kolbo.ai/api/v1/generate/video-from-video \
-H "X-API-Key: kolbo_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veed/subtitles",
"video_url": "https://media.kolbo.ai/videos/talking-clip.mp4",
"preset": "glass",
"source_language": "en-US",
"translation_language": "es-ES"
}'Input limits
There is no generic server-side check of max_images, max_videos, max_elements or the source-length fields on the model record. A few families validate their own inputs before any charge:
- Seedance (
seedance-2…): the source must be Kolbo-hosted and at least the model'smin_video_durationlong (400/VIDEO_TOO_SHORT); the edit models take one model per request. - Wan 3.0 (
wan3.0-video-to-video,wan3.0-prime-video-to-video): a source abovemax_video_durationreturns400/VIDEO_TOO_LONG; adurationabove the longestsupported_durationsentry returns400/DURATION_NOT_SUPPORTED. - FLUX 3 Edit Video (
flux-3-edit-video): sources of 15 s or longer return400/VIDEO_TOO_LONG. - Pruna P-Video (
prunaai/p-video-*): source length and reference-image count are checked (VIDEO_TOO_LONG,MISSING_REFERENCE_IMAGE,TOO_MANY_REFERENCE_IMAGES). - Morphious / Genjutsu: exactly one source video plus a mode-specific reference-image range, duration and resolution (
400/INVALID_MORPHIOUS_INPUTorINVALID_GENJUTSU_INPUT).
For every other model, validate against the model record yourself — over-sending fails at the provider mid-generation instead of returning a clean 400.
Billing
Most models are billed per second of the probed source video (motion-control models: the driving video), not the duration you request. Exceptions: Seedance edit and extend models add their extra input / requested output seconds on top of the source; VEED Subtitles bills a 60-second minimum; Luma Ray 3.2 bills the selected 5 s or 10 s output tier; Topaz Slow Motion bills the slowed-down output length; Runway Aleph 2.0 bills at least 2 seconds. Read the settled cost from credits_used on the completed status.
Examples
cURL with URL
First fetch identifiers from GET /api/v1/models?type=video_from_video, then pass the identifier value as model. The source video must already be on Kolbo storage:
curl -X POST https://api.kolbo.ai/api/v1/generate/video-from-video \
-H "X-API-Key: kolbo_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-identifier",
"prompt": "Transform into anime style with vibrant colors",
"video_url": "https://media.kolbo.ai/videos/original-clip.mp4",
"aspect_ratio": "16:9"
}'cURL with File Upload
curl -X POST https://api.kolbo.ai/api/v1/generate/video-from-video \
-H "X-API-Key: kolbo_live_YOUR_API_KEY" \
-F "model=your-model-identifier" \
-F "prompt=Transform into anime style with vibrant colors" \
-F "[email protected]"Timestamp-Anchored Keyframes
Models that support keyframes let you pin specific images to specific moments in the output. The keyframe images must already live on Kolbo storage — upload them through the Media Library first.
Check keyframe capability on GET /api/v1/models first: supports_keyframes / max_keyframes report whether the model accepts keyframes and how many. Send keyframes to a model that does not support them and they are silently dropped along with source_fps / source_duration_seconds — the request still succeeds as a plain video-to-video, so verify with a small test generation before relying on them.
curl -X POST https://api.kolbo.ai/api/v1/generate/video-from-video \
-H "X-API-Key: kolbo_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "your-keyframe-capable-model-identifier",
"video_url": "https://media.kolbo.ai/videos/source.mp4",
"prompt": "Match the reference frames",
"source_fps": 24,
"source_duration_seconds": 8,
"keyframes": [
{ "image_url": "https://media.kolbo.ai/images/frame-a.png", "timestamp_seconds": 0 },
{ "image_url": "https://media.kolbo.ai/images/frame-b.png", "timestamp_seconds": 4.5 }
]
}'Model identifiers come from GET /api/v1/models?type=video_from_video. Always fetch the latest list rather than hardcoding identifiers, as models may change over time.
JavaScript
const API_KEY = "kolbo_live_YOUR_API_KEY";
// Fetch available video-to-video models
async function initModels() {
const res = await fetch("https://api.kolbo.ai/api/v1/models?type=video_from_video", {
headers: { "X-API-Key": API_KEY },
});
const data = await res.json();
console.log("Available models:", data.models.map((m) => m.identifier));
}
async function main() {
await initModels();
const response = await fetch("https://api.kolbo.ai/api/v1/generate/video-from-video", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "your-model-identifier", // required — no auto-select on this endpoint
prompt: "Transform into anime style with vibrant colors",
video_url: "https://media.kolbo.ai/videos/original-clip.mp4",
aspect_ratio: "16:9",
}),
});
const started = await response.json();
if (!started.success) throw new Error(started.error);
const result = await pollUntilDone(started.generation_id, started.poll_interval_hint);
if (result.state !== "completed") throw new Error(result.error || result.state);
console.log("Video URL:", result.result.urls[0]); // urls is always an array
}
const TERMINAL = new Set(["completed", "failed", "cancelled"]);
// Minimal loop. A production client should also handle transient HTTP errors and
// an overall timeout — see /docs/developer-api/polling-and-cancellation.
async function pollUntilDone(generationId, intervalSeconds) {
while (true) {
await new Promise((r) => setTimeout(r, intervalSeconds * 1000));
const status = await fetch(
`https://api.kolbo.ai/api/v1/generate/${generationId}/status`,
{ headers: { "X-API-Key": API_KEY } }
).then((r) => r.json());
if (TERMINAL.has(status.state)) return status;
}
}
main();Python
import requests
import time
API_KEY = "kolbo_live_YOUR_API_KEY"
BASE_URL = "https://api.kolbo.ai/api"
HEADERS = {"X-API-Key": API_KEY}
# Fetch available video-to-video models
models_res = requests.get(
f"{BASE_URL}/v1/models",
headers=HEADERS,
params={"type": "video_from_video"},
)
print("Available models:", [m["identifier"] for m in models_res.json()["models"]])
# --- Option A: Using URL ---
response = requests.post(
f"{BASE_URL}/v1/generate/video-from-video",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "your-model-identifier", # required — no auto-select on this endpoint
"prompt": "Transform into anime style with vibrant colors",
"video_url": "https://media.kolbo.ai/videos/original-clip.mp4",
"aspect_ratio": "16:9",
},
)
data = response.json()
print("Generation ID:", data["generation_id"])
# --- Option B: Using file upload ---
# with open("original-clip.mp4", "rb") as vid:
# response = requests.post(
# f"{BASE_URL}/v1/generate/video-from-video",
# headers=HEADERS,
# files={"files": vid},
# data={
# "model": "your-model-identifier",
# "prompt": "Transform into anime style with vibrant colors",
# },
# )
# data = response.json()
TERMINAL = {"completed", "failed", "cancelled"}
# Minimal loop. Add transient-error retries and an overall timeout for production
# — see /docs/developer-api/polling-and-cancellation.
while True:
time.sleep(data["poll_interval_hint"])
status = requests.get(
f"{BASE_URL}/v1/generate/{data['generation_id']}/status",
headers=HEADERS,
).json()
if status["state"] in TERMINAL:
break
if status["state"] != "completed":
raise Exception(status.get("error", status["state"]))
print("Video URL:", status["result"]["urls"][0]) # urls is always a listResponse
This endpoint is asynchronous and fire-and-forget: the POST returns as soon as the job is queued and never contains a video.
Polling is the only completion mechanism. Kolbo never calls you back: there is no webhook, no callback_url field on this request body, and no route delivers outbound notifications. Socket.IO events are the web app's internal transport and are not part of the API contract — API-key generations are registered so the shared progress emitter drops their events, and the few emit sites that bypass that check are undocumented, unversioned and unsafe to build on. After the POST, loop against GET /api/v1/generate/{generation_id}/status until state is completed, failed or cancelled. Full contract: Polling & Cancellation.
Generation Started
{
"success": true,
"generation_id": "68f2c1a9b4e5d6f7a8b9c0d1",
"type": "video_from_video",
"model": "your-model-identifier",
"credits_charged": null,
"poll_url": "/v1/generate/68f2c1a9b4e5d6f7a8b9c0d1/status",
"poll_interval_hint": 8,
"session_id": "…",
"project_id": "…"
}| Field | Type | Notes |
|---|---|---|
generation_id | string | Mongo ObjectId. This is what you poll and cancel with. |
type | string | Always "video_from_video" |
model | string | The identifier that was submitted, after alias resolution — this endpoint has no Smart Select, so model is required |
credits_charged | null | Always null on this endpoint — the video-to-video pipeline reports no estimate at submit time. Read credits_used from the completed status. |
poll_url | string | The status path without the /api prefix. Prepend https://api.kolbo.ai/api. |
poll_interval_hint | number | Suggested seconds between polls — 8 here |
session_id / project_id | string | Where the generation lives in the Kolbo app |
Completed Status
GET /api/v1/generate/{generation_id}/status
{
"success": true,
"generation_id": "68f2c1a9b4e5d6f7a8b9c0d1",
"type": "video_from_video",
"state": "completed",
"progress": 100,
"result": {
"urls": ["https://media.kolbo.ai/videos/.../output.mp4"],
"thumbnail_url": null,
"duration": 5,
"aspect_ratio": "16:9",
"prompt_used": "Transform into anime style with vibrant colors",
"model": "your-model-identifier",
"created_at": "2026-04-12T10:00:00.000Z"
},
"credits_used": 50,
"credits_breakdown": [
{ "model": "your-model-identifier", "amount": 50, "base": 50, "final": 50, "duration_multiplier": null, "pricing": null }
]
}The output lives in result.urls — always an array of strings, even though this endpoint produces exactly one video. Read urls[0].
result (and credits_used / credits_breakdown) appear only under state: "completed"; a processing body has exactly five keys and no result at all. There is no partial or streaming read.
result.thumbnail_url is usually null here — video-to-video has no source still to fall back on, so it is populated only when the pipeline generated a poster frame. result.duration is the recorded output length when the pipeline stored one; otherwise it falls back to the duration you sent (stored as a string) or null.
Optional result keys, present only when they have data: model_name (display name of the model that ran), playback_urls (browser-playable companions to urls, null per clip when the master already plays everywhere), reference_images (the references the generation actually conditioned on, including injected Visual DNA stills), visual_dna ([{ id, name, thumbnail_url }] for the DNAs used) and style ({ id, name, cover, custom } for a Morphious style).
credits_used is the authoritative, multiplier-adjusted cost, not credits_charged from the submit response.
Failure and cancellation
A failed generation is still an HTTP 200 with success: true — the failure is in state, with an error string and a best-effort failure object. cancelled carries neither result nor error, so treat all three terminal states explicitly. Failed generations are not charged. See Polling & Cancellation.
Tips
- Pick the model first.
max_images,max_videos,max_elements,min_video_duration, andmax_video_durationon the model record describe which extra inputs the model takes and what source length it is built for. Only some families enforce them (see Input limits), so validate against the model record yourself before submitting. - Upload source videos, character images and keyframe images to the Media Library first and pass the returned URLs — an external
video_url, motion-control character image or keyframe image is rejected. - Video-to-video generation typically takes several minutes depending on the model and duration.
- Be descriptive in your prompt — specify the target style, mood, and any visual changes you want applied.
- When using file uploads, the limit is 100 MB per file.
- Read the settled cost from
credits_usedon the completed status response — see Credits and Billing. - Use
poll_interval_hintfrom the initial response to set your polling interval. - Check
supported_durationsandsupported_aspect_ratioson each model via the Models endpoint before requesting specific values.
Related
Video Generation
Text-to-video and image-to-video
Video Editing and Trim
Upscale, reframe, extend, lipsync, inpaint, and frame-accurate trimming
Media Library
Upload source videos and keyframe images to Kolbo storage
Models and Pricing
Model catalog and the per-model input caps referenced above
Polling and Cancellation
The state machine, the reference poll loop, failures and cancel