kando.
THE KANDO VIDEO API

One prompt.
A video in return.

Bring video generation into your product. Send a description, follow the progress, and download the finished video.

Prompt to video Background generation Downloadable MP4
01 / START WITH A PROMPT

Describe it. We handle the steps.

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()));
Generation takes time.

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.

02 / A RESULT YOU CAN USE

A video when it’s ready.

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
}

In progress

video_url and output are null while the video is being made. Progress is saved on the server.

Failed or cancelled

Do not attempt a download. A failure includes an error code and message. Failed jobs require a new request to retry.

Video output

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.

03 / THE WHOLE API

Four endpoints. One workflow.

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.

POST/v1/videos

Generate a video

Send { 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.

GET/v1/videos/:id

Check a video

Returns 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.

GET/v1/videos/:id/content

Download the MP4

Returns the full edited video as video/mp4. Requires the same bearer key. Returns HTTP 409 until a completed video is available.

POST/v1/videos/:id/cancel

Cancel generation

Stops an active generation. Poll the video until its status is terminal. Cancelling an already finished video keeps its result.

04 / CONNECT YOUR SERVICE

Use your Kando workspace.

These examples use your own running Kando service. Public self-serve API keys and billing are not available yet.

  1. Start Kando

    In the repository, run pnpm dev for the local gateway and store, and pnpm web for the website.

  2. Connect your application

    Set KANDO_URL and KANDO_API_KEY on your application server. Keep service credentials out of browser code.

  3. Open the video studio

    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.