Kolbo.AIKolbo.AI Docs
Developer API

First & Last Frame

Generate videos by interpolating between a first and last frame image using the Kolbo API.

Generate videos by providing a first and last frame image. The AI interpolates between the two frames, creating smooth animated transitions.

Smart Select (recommended): Omit the model field and Kolbo automatically picks the best model for your input. This is the default and recommended approach for most use cases.

Model identifiers are Kolbo-specific. Never hardcode model identifiers — always fetch the current list from GET /api/v1/models?type=first_last_frame first. Models may be added, renamed, or retired at any time.

Endpoint

POST /api/v1/generate/first-last-frame

Request Body

Accepts application/json or multipart/form-data (when uploading files).

You must provide frames in one of two ways — do not mix them:

  • URL mode: Provide first_frame_url and last_frame_url as JSON fields.
  • File mode: Upload exactly 2 image files via multipart files field (first frame, then last frame). Max 10 MB total.
FieldTypeRequiredDescription
first_frame_urlstringConditionalURL of the first frame image (required if not uploading files)
last_frame_urlstringConditionalURL of the last frame image (required if not uploading files)
filesmultipartConditionalExactly 2 image files: first frame then last frame (required if not using URLs)
promptstringNoDescribe the transition between frames
modelstringNoModel identifier from GET /api/v1/models?type=first_last_frame (default: auto-select)
durationnumberNoDuration in seconds (default: 5)
aspect_ratiostringNo"16:9", "9:16", "1:1" (default: "16:9")
enhance_promptbooleanNoEnhance prompt (default: true)
visual_dna_idsarrayNoVisual DNA IDs for consistency (max 3)

Do not mix URLs and files. Provide either both first_frame_url and last_frame_url, OR exactly two multipart files. Mixing will return a 400 error.

Examples

URL Mode

cURL (Smart Select — recommended):

curl -X POST https://api.kolbo.ai/api/v1/generate/first-last-frame \
  -H "X-API-Key: kolbo_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_frame_url": "https://example.com/sunrise.jpg",
    "last_frame_url": "https://example.com/sunset.jpg",
    "prompt": "Smooth time-lapse transition from sunrise to sunset over a cityscape",
    "duration": 5,
    "aspect_ratio": "16:9"
  }'

JavaScript:

const API_KEY = "kolbo_live_YOUR_API_KEY";

async function main() {
  // Optional: fetch available models
  // const models = await fetch("https://api.kolbo.ai/api/v1/models?type=first_last_frame", {
  //   headers: { "X-API-Key": API_KEY }
  // }).then(r => r.json());
  // console.log("Available models:", models);

  const response = await fetch("https://api.kolbo.ai/api/v1/generate/first-last-frame", {
    method: "POST",
    headers: {
      "X-API-Key": API_KEY,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      first_frame_url: "https://example.com/sunrise.jpg",
      last_frame_url: "https://example.com/sunset.jpg",
      prompt: "Smooth time-lapse transition from sunrise to sunset over a cityscape",
      duration: 5,
      aspect_ratio: "16:9"
    })
  });

  const data = await response.json();
  console.log("Generation ID:", data.generation_id);
  console.log("Poll URL:", data.poll_url);

  // Poll for completion
  const pollForResult = async (generationId) => {
    while (true) {
      await new Promise((r) => setTimeout(r, data.poll_interval_hint * 1000));
      const status = await fetch(
        `https://api.kolbo.ai/api/v1/generate/${generationId}/status`,
        { headers: { "X-API-Key": API_KEY } }
      ).then((r) => r.json());

      console.log("State:", status.state, "Progress:", status.progress);

      if (status.state === "completed") {
        console.log("Video URL:", status.result.urls[0]);
        return status;
      }
      if (status.state === "failed") {
        console.error("Generation failed:", status.error);
        return status;
      }
    }
  };

  await pollForResult(data.generation_id);
}

main();

Python:

import requests
import time

API_KEY = "kolbo_live_YOUR_API_KEY"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

# Optional: fetch available models
# models = requests.get(
#     "https://api.kolbo.ai/api/v1/models?type=first_last_frame",
#     headers={"X-API-Key": API_KEY},
# ).json()
# print("Available models:", models)

response = requests.post(
    "https://api.kolbo.ai/api/v1/generate/first-last-frame",
    headers=HEADERS,
    json={
        "first_frame_url": "https://example.com/sunrise.jpg",
        "last_frame_url": "https://example.com/sunset.jpg",
        "prompt": "Smooth time-lapse transition from sunrise to sunset over a cityscape",
        "duration": 5,
        "aspect_ratio": "16:9",
    },
)

data = response.json()
print("Generation ID:", data["generation_id"])
print("Poll URL:", data["poll_url"])

# Poll for completion
generation_id = data["generation_id"]
poll_interval = data.get("poll_interval_hint", 8)

while True:
    time.sleep(poll_interval)
    status = requests.get(
        f"https://api.kolbo.ai/api/v1/generate/{generation_id}/status",
        headers={"X-API-Key": API_KEY},
    ).json()

    print(f"State: {status['state']}  Progress: {status.get('progress', 0)}%")

    if status["state"] == "completed":
        print("Video URL:", status["result"]["urls"][0])
        break
    if status["state"] == "failed":
        print("Error:", status.get("error"))
        break

File Mode

cURL with file uploads:

curl -X POST https://api.kolbo.ai/api/v1/generate/first-last-frame \
  -H "X-API-Key: kolbo_live_YOUR_API_KEY" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "prompt=Smooth transition between the two frames" \
  -F "duration=5" \
  -F "aspect_ratio=16:9"

Python with file uploads:

import requests
import time

API_KEY = "kolbo_live_YOUR_API_KEY"

files = [
    ("files", ("first-frame.jpg", open("first-frame.jpg", "rb"), "image/jpeg")),
    ("files", ("last-frame.jpg", open("last-frame.jpg", "rb"), "image/jpeg")),
]

response = requests.post(
    "https://api.kolbo.ai/api/v1/generate/first-last-frame",
    headers={"X-API-Key": API_KEY},
    files=files,
    data={
        "prompt": "Smooth transition between the two frames",
        "duration": "5",
        "aspect_ratio": "16:9",
    },
)

data = response.json()
print("Generation ID:", data["generation_id"])

# Poll for completion
generation_id = data["generation_id"]
poll_interval = data.get("poll_interval_hint", 8)

while True:
    time.sleep(poll_interval)
    status = requests.get(
        f"https://api.kolbo.ai/api/v1/generate/{generation_id}/status",
        headers={"X-API-Key": API_KEY},
    ).json()

    print(f"State: {status['state']}  Progress: {status.get('progress', 0)}%")

    if status["state"] == "completed":
        print("Video URL:", status["result"]["urls"][0])
        break
    if status["state"] == "failed":
        print("Error:", status.get("error"))
        break

With Specific Model

First, fetch available models:

curl https://api.kolbo.ai/api/v1/models?type=first_last_frame \
  -H "X-API-Key: kolbo_live_YOUR_API_KEY"

Then use a model identifier from the response:

curl -X POST https://api.kolbo.ai/api/v1/generate/first-last-frame \
  -H "X-API-Key: kolbo_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_frame_url": "https://example.com/sunrise.jpg",
    "last_frame_url": "https://example.com/sunset.jpg",
    "prompt": "Smooth time-lapse transition from sunrise to sunset",
    "model": "MODEL_IDENTIFIER_FROM_MODELS_ENDPOINT",
    "duration": 5
  }'

Model identifiers come from GET /api/v1/models?type=first_last_frame. Always fetch the latest list rather than hardcoding identifiers, as models may change over time.

Response

Initial Response

{
  "success": true,
  "generation_id": "flf123",
  "type": "first_last_frame",
  "model": "auto",
  "credits_charged": 50,
  "poll_url": "/api/v1/generate/flf123/status",
  "poll_interval_hint": 8
}

Completed Status

{
  "success": true,
  "generation_id": "flf123",
  "type": "first_last_frame",
  "state": "completed",
  "progress": 100,
  "result": {
    "urls": ["https://cdn.kolbo.ai/videos/..."],
    "thumbnail_url": "https://cdn.kolbo.ai/thumbs/...",
    "duration": 5,
    "aspect_ratio": "16:9",
    "prompt_used": "Smooth time-lapse transition from sunrise to sunset over a cityscape",
    "model": "auto",
    "created_at": "2026-04-12T10:30:00.000Z"
  }
}

Tips

  • Use Smart Select (the default). Omit the model field and Kolbo picks the best model for your input. This is the simplest and most future-proof approach.
  • First & Last Frame generation typically takes 1-5 minutes depending on the model and duration.
  • Both frames should have the same aspect ratio for best results. The API may crop or pad mismatched frames.
  • The prompt field is optional but recommended — it guides the interpolation style (e.g., "smooth camera pan", "dramatic zoom", "time-lapse").
  • File uploads are limited to 10 MB total (both files combined).
  • Credits are charged per second: model.credit x duration.
  • Use poll_interval_hint from the initial response to set your polling interval.
  • Check supported_durations and supported_aspect_ratios on each model via the Models endpoint before requesting specific values.