In progress
video_url and output are null while the video is being made. Progress is saved on the server.
Bring video generation into your product. Send a description, follow the progress, and download the finished video.
Only prompt is required. Kando prepares the script, builds the scene, and renders the video automatically. No session setup or follow-up messages needed.
// Run on your server with your Kando service credentials.
const base = process.env.KANDO_URL;
const headers = {
Authorization: `Bearer ${process.env.KANDO_API_KEY}`,
'Content-Type': 'application/json',
};
const response = await fetch(`${base}/v1/videos`, {
method: 'POST', headers,
body: JSON.stringify({
prompt: 'An 8-second video of two strangers at a café. A slow push-in.',
}),
});
if (!response.ok) throw new Error(await response.text());
let video = await response.json();
console.log(video.id); // Save this ID to resume polling later.
const deadline = Date.now() + 30 * 60_000;
while (video.status === 'queued' || video.status === 'in_progress') {
if (Date.now() > deadline) {
throw new Error('Still generating; resume with GET ' + video.status_url);
}
await new Promise(resolve => setTimeout(resolve, 5000));
const status = await fetch(`${base}${video.status_url}`, { headers });
if (!status.ok) throw new Error(await status.text());
video = await status.json();
}
if (video.status !== 'completed') {
throw new Error(video.error?.message || video.status);
}
// Public CDN URLs do not need your service credentials.
const url = new URL(video.video_url, base);
const mp4 = await fetch(url, {
headers: url.origin === new URL(base).origin ? headers : {},
});
if (!mp4.ok) throw new Error(await mp4.text());
const { writeFile } = await import('node:fs/promises');
await writeFile('video.mp4', Buffer.from(await mp4.arrayBuffer()));The create request returns a task, not the video bytes. Save its ID and poll for completion. Closing the connection does not cancel generation. A lost create response may still have started work; check your workspace before submitting again.
A successful text response is not enough: the job completes only when the full rendered MP4 has been saved. The following is an illustrative completed response; IDs and file metadata come from your request.
{
"id": "<video-id>",
"object": "video",
"prompt": "An 8-second café encounter. A slow push-in.",
"status": "completed",
"created_at": "<ISO timestamp>",
"status_url": "/v1/videos/<video-id>",
"video_url": "https://cdn.vframe.cc/kando/videos/<video-id>/<sha256>.mp4",
"output": {
"path": "export/review.mp4",
"sha256": "<file hash>",
"size": 1234567,
"mime": "video/mp4"
},
"error": null
}video_url and output are null while the video is being made. Progress is saved on the server.
Do not attempt a download. A failure includes an error code and message. Failed jobs require a new request to retry.
Completed jobs provide a downloadable MP4. Describe the style, action, and pacing in your prompt; the result depends on the tools available in your workspace.
Call your gateway or standalone agent with Authorization: Bearer YOUR_API_KEY. URLs in responses are relative to that service and require authentication. Invalid prompts return 400; unknown video IDs return 404.
/v1/videosSend { prompt, model?, webhook_url?, max_duration_seconds? }. Prompt is required, up to 12,000 characters. Returns HTTP 202 once the request is saved in the queue. Reuse an Idempotency-Key header when retrying a submission. Webhooks require a registered HTTPS receiver. max_duration_seconds caps the delivered length: the director plans to it and a longer film fails as invalid_video.
/v1/videos/:idReturns queued, in_progress, completed, failed, or cancelled. Queued videos include queue_position and start automatically when capacity is available. A completed video has passed playback and storage verification, and includes video_url and output metadata. Interrupted work can resume up to two times under the same ID. Poll every 5 seconds; save the ID to pick up later.
/v1/videos/:id/contentReturns the full edited video as video/mp4. Requires the same bearer key. Returns HTTP 409 until a completed video is available.
/v1/videos/:id/cancelStops an active generation. Poll the video until its status is terminal. Cancelling an already finished video keeps its result.
These examples use your own running Kando service. Public self-serve API keys and billing are not available yet.
In the repository, run pnpm dev for the local gateway and store, and pnpm web for the website.
Set KANDO_URL and KANDO_API_KEY on your application server. Keep service credentials out of browser code.
The website reads the same connection from the root .env. Hosted shared workspaces also require KANDO_WEB_ACCESS_KEY. Everyone with that workspace key can access its projects. Manage invitation codes and recorded model costs at /internal; invited visitors only access projects created with their code.
Advanced project history, files, and model controls remain available through the existing session API. A video ID also identifies its underlying project.