Developer API Overview
Programmatically generate images, videos, music, speech, and sound effects with the Kolbo API.
The Kolbo Developer API lets you programmatically access 100+ AI models for generating images, videos, music, speech, and sound effects. Use it from any language, or integrate directly into Claude Code via our MCP server.
Quick Start
1. Get an API Key
Create a key from the Developer Console or via the API:
curl -X POST https://api.kolbo.ai/api/api-keys \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "My App"}'The key is in the fullKey field of the response (HTTP 201). Besides the required name, the body accepts permissions (array, optional, values read and write only — default ["read","write"]; anything else is a 400) and expiresInDays (number, optional, default 365, clamped to 1–730). You may hold at most 50 active keys; creating the 51st returns a 400. If you lose the key you can re-reveal it with GET /api/api-keys/:keyId/reveal (same JWT auth, rate limited) or from the Developer Console.
2. Generate an Image
When you omit the model field, Kolbo uses Smart Select to automatically pick the best model for your prompt. This is the recommended approach for most use cases.
curl -X POST https://api.kolbo.ai/api/v1/generate/image \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "A sunset over mountains", "aspect_ratio": "16:9"}'Response:
{
"success": true,
"generation_id": "abc123",
"type": "image",
"model": "auto",
"credits_charged": 12,
"poll_url": "/v1/generate/abc123/status",
"poll_interval_hint": 3,
"session_id": "68f...",
"project_id": "68e..."
}model echoes back what the server resolved your request to. Omitting model echoes "auto" on every Smart-Select-routed type (image, image edit, video, video-from-image, elements, first-last-frame, lipsync, video-to-video, chat, transcription, 3D). POST /v1/generate/music, /v1/generate/speech, and /v1/generate/sound instead substitute a concrete default identifier for that type and echo it; POST /v1/edit/image and POST /v1/edit/video echo null. poll_interval_hint is seconds: 2 for chat, 3 for image and image-edit, 5 for sound and Creative Director, 8 for everything else. session_id and project_id tell you where the generation landed in the app (project_id is the auto-created "API Generations" project when you did not pass one).
3. Poll for Results
Replace abc123 with the generation_id from step 2:
curl https://api.kolbo.ai/api/v1/generate/abc123/status \
-H "X-API-Key: YOUR_API_KEY"When complete:
{
"success": true,
"generation_id": "abc123",
"type": "image",
"state": "completed",
"progress": 100,
"result": {
"urls": ["https://cdn.kolbo.ai/..."],
"thumbnail_url": "https://cdn.kolbo.ai/...",
"model": "nano-banana-2",
"prompt_used": "A breathtaking sunset...",
"created_at": "2026-07-27T09:14:02.913Z"
},
"credits_used": 12,
"credits_breakdown": [
{ "model": "nano-banana-2", "amount": 12, "base": 10, "final": 12 }
]
}result.model is always the model that actually ran — Smart Select's router id is never surfaced, so a request you submitted with model: "auto" comes back with the resolved identifier (or null if the generation record never recorded one). credits_used / credits_breakdown are the real multiplier-adjusted spend and are present only once state === "completed". On state === "failed" you get error (a string) plus a structured failure object with message, category, code, retryable, severity, and provider — every one of those sub-fields except message can be null, and a failed Creative Director batch returns error with no failure object at all. See Polling & Cancellation.
4. Detecting Success
Never branch on an exact HTTP status. The submit call is 2xx on success, but which 2xx differs per endpoint — 200 (image, 3D, Shorts analyze), 201 (/generate/image-edit), and 202 Accepted (/edit/image, /edit/video, speech, sound, lipsync, elements, first-last-frame, Creative Director, video trim) are all in use, and an endpoint's code may change. A client that tests status === 200 will reject perfectly good jobs.
There is also no single success flag: one failure mode (TRACKING_ERROR) returns a 2xx with success: false, and errors from the global middleware carry status: false / message instead of success: false / error. The one check that holds everywhere is:
const started = await res.json();
if (!res.ok || started.success === false || started.status === false) {
throw new Error(started.error ?? started.message ?? `HTTP ${res.status}`);
}Then confirm you actually got a job handle — generation_id on every generation endpoint, message_id on POST /v1/chat, jobId on video trim, and data.jobId on Shorts Creator. See Errors & Limits.
5. Using the Output URL
Treat output URLs as opaque and do not hardcode the host. Finished assets are served from Kolbo's CDN, and more than one host appears across these docs (media.kolbo.ai and cdn.kolbo.ai). Never allow-list, string-match, or reconstruct a host — read the exact string out of result.urls[] and use it verbatim.
The URLs in result are plain CDN links: they carry no query string, no signature, and none of your credentials. Fetch them with an ordinary GET and do not attach X-API-Key — that header belongs to api.kolbo.ai, not to the CDN host.
No lifetime is published for these URLs. Nothing in this API guarantees a finished asset stays reachable at the same address forever, and permanently deleting the media item (DELETE /v1/media/:id/permanent) removes the underlying file. If the asset matters to you, download the bytes into your own storage as soon as the generation completes, rather than persisting the Kolbo URL as your system of record.
If you lose a URL — or need one long after the poll loop ended — do not re-generate. Re-resolve it:
GET /v1/media/:idaccepts a generation id as well as a media id, and returns that generation's media item. So thegeneration_idyou kept is enough to find the asset again.GET /v1/media?category=ai(plusproject_id/type/search) lists everything the account has produced.
Both are documented in Media Library.
Full Example (JavaScript)
const API_KEY = "YOUR_API_KEY";
const BASE = "https://api.kolbo.ai/api/v1";
async function generateImage(prompt) {
const res = await fetch(`${BASE}/generate/image`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({ prompt, aspect_ratio: "16:9" })
});
const { generation_id } = await res.json();
while (true) {
await new Promise((r) => setTimeout(r, 3000));
const status = await fetch(`${BASE}/generate/${generation_id}/status`, {
headers: { "X-API-Key": API_KEY }
}).then((r) => r.json());
if (status.state === "completed") return status.result.urls;
if (status.state === "failed") throw new Error(status.error);
// `cancelled` carries neither `result` nor `error`. Without this branch the
// loop polls a cancelled generation forever.
if (status.state === "cancelled") throw new Error("Generation was cancelled");
}
}
generateImage("A sunset over mountains").then(console.log);Full Example (Python)
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE = "https://api.kolbo.ai/api/v1"
def generate_image(prompt):
res = requests.post(
f"{BASE}/generate/image",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={"prompt": prompt, "aspect_ratio": "16:9"}
)
generation_id = res.json()["generation_id"]
while True:
time.sleep(3)
status = requests.get(
f"{BASE}/generate/{generation_id}/status",
headers={"X-API-Key": API_KEY}
).json()
if status["state"] == "completed":
return status["result"]["urls"]
if status["state"] == "failed":
raise Exception(status["error"])
# `cancelled` carries neither `result` nor `error`. Without this branch the
# loop polls a cancelled generation forever.
if status["state"] == "cancelled":
raise Exception("Generation was cancelled")
urls = generate_image("A sunset over mountains")
print(urls)Generation Types
Every endpoint below returns immediately with a generation_id (POST /v1/chat calls the same handle message_id) and is polled at GET /v1/generate/:generation_id/status. Video Trim is the one exception — it runs on its own job collection and is not resolvable on the generic status route. It returns no poll_url: Video Trim replies 202 with jobId (poll GET /v1/video/trim/:jobId — ignore the pollingUrl it also returns, which points at the in-app route). Creative Director is resolvable on it (the generic route detects the batch and internally delegates to the per-scene endpoint), but the dedicated GET /v1/generate/creative-director/:id/status path returns the same payload with one less hop. See Polling & Cancellation.
| Type | Endpoint | Docs |
|---|---|---|
| Chat | POST /v1/chat | Chat |
| Image | POST /v1/generate/image | Image Generation |
| Image Edit (prompt-driven) | POST /v1/generate/image-edit | Image Editing |
| Image Edit (targeted operations) | POST /v1/edit/image | Image Editing |
| Video (text) | POST /v1/generate/video | Video Generation |
| Video (from image) | POST /v1/generate/video/from-image | Video Generation |
| Video (from video) | POST /v1/generate/video-from-video | Video to Video |
| Video edit operations | POST /v1/edit/video | Video Editing |
| Elements (ref → video) | POST /v1/generate/elements | Elements |
| First-Last Frame | POST /v1/generate/first-last-frame | First-Last Frame |
| Lipsync | POST /v1/generate/lipsync | Lipsync |
| Music | POST /v1/generate/music | Music Generation |
| Speech | POST /v1/generate/speech | Speech & Sound |
| Sound Effects | POST /v1/generate/sound | Speech & Sound |
Creative Director (preferred poll path: GET /v1/generate/creative-director/:id/status) | POST /v1/generate/creative-director | Creative Director |
| 3D Model | POST /v1/generate/3d | 3D Generation |
| Transcription | POST /v1/transcribe | Transcription |
| Video Trim | POST /v1/video/trim | Video Editing |
Rate limits differ by endpoint. Image endpoints (/v1/generate/image, /v1/generate/image-edit, /v1/edit/image) allow 30 requests/minute; /v1/transcribe allows 100/minute; every other generation endpoint defaults to 10/minute. See Errors & Limits.
Shorts Creator is HTTP-only — the @kolbo/mcp server does not register tools for it, so an MCP client has to call these endpoints directly with an X-API-Key header.
Visual DNA
Create reusable visual identities for characters, products, or styles, then attach them to any generation for consistency.
| Endpoint | Description |
|---|---|
POST /v1/visual-dna | Create a Visual DNA from reference images |
GET /v1/visual-dna | List your Visual DNAs |
GET /v1/visual-dna/:id | Get Visual DNA details |
DELETE /v1/visual-dna/:id | Delete a Visual DNA |
See Visual DNA for details.
Moodboards
Discover and apply style templates (moodboards) to guide the visual direction of your generations.
| Endpoint | Description |
|---|---|
GET /v1/moodboards | List available moodboards (personal + presets) |
GET /v1/moodboards/:id | Get moodboard details |
Create, update, and delete moodboards with POST /v1/moodboards, PUT /v1/moodboards/:id, and DELETE /v1/moodboards/:id. Pass moodboard_id to image generation, image editing, or Creative Director requests. See Moodboards for details.
Color DNA
A saved color palette that becomes one project's grade. A project stores at most one palette (castColorPaletteId), and while it is set, generations that run inside that project are color-graded automatically. There is no account-wide palette — a generation with no resolved project gets no grade.
| Endpoint | Description |
|---|---|
GET /v1/color-palettes | List the user's palettes (personal + active-org scope). Query: page (default 1), limit (default 50, max 100), projectId. is_active means "is this project's grade" — without projectId every row comes back is_active: false |
POST /v1/color-palettes | Create a palette. Body: name (string, required, 1–100), colors (array, required, 1–10 of { hex: "#RRGGBB" required, name ≤60 chars, role: dominant | secondary | accent | background }), source_image_urls (≤5 URLs), is_active (bool, default true), projectId (string). It only becomes a grade when projectId is supplied and is_active is not false — otherwise it is just saved to the library |
PUT /v1/color-palettes/:id | Rename and/or replace colors / source_image_urls (owner only, never changes the grade). Any other body key is rejected with 400 |
DELETE /v1/color-palettes/:id | Delete a palette and clear it from every project that pointed at it |
POST /v1/color-palettes/:id/activate | Make this palette the grade for one project. Body: projectId (required — omitting it returns 400 "Open a project to set its Color DNA"; a viewer-only member gets 403) |
POST /v1/color-palettes/deactivate | Clear a project's grade. Body: projectId (required, same 400/403 rules) |
POST /v1/color-palettes/analyze | Extract colors from 1–5 image URLs. Body: image_urls (array, required, 1–5). Local pixel analysis, free, saves nothing |
projectId is camelCase on these routes (not project_id like the generation endpoints), and it is required on activate and deactivate.
skip_color_palette: true opts one request out of the project's grade without clearing it. Only four handlers read it: POST /v1/generate/image, /v1/generate/image-edit, /v1/generate/video, and /v1/generate/video/from-image. Other generation endpoints ignore the field.
See Color Palettes for details.
Cinematic Presets
| Endpoint | Description |
|---|---|
GET /v1/cinematic-presets | Cinematic preset ids grouped by dimension. The response is the bare grouped map — { "<dimension>": [{ id, name, description, thumbnail_url, preview_url?, sort_order, bundle? }, …] } — not an envelope, and it is ETag-cached (send If-None-Match and expect 304). The dimension keys are data-driven (the catalog can serve looks, camera, lens, focal_length, aperture, angle, shot_type, lighting, color_palette, genre, moveset; only dimensions with active presets appear), so read them from the response rather than hardcoding |
Pass the ids you want in the optional cinematic object on POST /v1/generate/image and POST /v1/generate/image-edit. See Cinematic Presets.
Music Library
Search Kolbo's catalog of licensed, ready-made background tracks (distinct from music generation). Discovery is free; the two acquisition endpoints are paid.
| Endpoint | Description |
|---|---|
POST /v1/music-library/search | Keyword search + genre/mood/bpm/duration filters |
POST /v1/music-library/analyze-script | AI: turn a script into a music search |
GET /v1/music-library/catalog | Browse the catalog (paginated) |
GET /v1/music-library/facets | Available genres, moods, instruments + ranges |
GET /v1/music-library/track/:id/audio | Downloadable 128/320/WAV URLs |
GET /v1/music-library/track/:id/related | Stems + alternate versions |
GET /v1/music-library/track/:id/lyrics | Lyrics text + theme |
POST /v1/music-library/clean/:trackId | Paid — acquire a clean, unwatermarked MP3/WAV |
POST /v1/music-library/import | Paid — acquire a clean file and copy it into the media library |
The two acquisition endpoints spend a vendor credit on the first call, with no confirmation step, and require a write-enabled API key — a read-only key gets 403 API_KEY_READ_ONLY. Both are idempotent through the request id you supply, so send a stable one when retrying. They also share a much tighter rate limit than the free discovery endpoints.
See Music Library for details.
Stock Library
Unified, multi-source stock media — photos, videos, illustrations, vectors, 3D models, sound effects, and music. Find b-roll, references, and project assets. All endpoints are free (no credits).
Sources reachable from the API: kolbo-ai (Kolbo's own AI sound effects, music, and images), pexels, unsplash, pixabay, coverr, freesound, sketchfab. Call GET /v1/stock/sources for the live list and each source's supported media types and filters.
The licensed production-music source (music, and its internal alias synci) is not exposed on the stock endpoints. GET /v1/stock/search?source=music and GET /v1/stock/asset/music/:id return 404 STOCK_NOT_FOUND; GET /v1/stock/sources filters the source out of its list, and GET /v1/stock/categories?source=music returns an empty 200 ({ success: true, categories: [], count: 0 }). GET /v1/stock/collections only ever serves Kolbo's own SFX collections (mediaType must be sfx; anything else returns an empty list). Reach the licensed catalog through the Music Library endpoints instead.
| Endpoint | Description |
|---|---|
GET /v1/stock/sources | List enabled sources + supported media types/filters |
GET /v1/stock/categories | Dynamic category/topic chips per source |
GET /v1/stock/collections | Kolbo SFX category collections + themed packs |
GET /v1/stock/search | Unified search (source=all interleaves providers) |
GET /v1/stock/asset/:source/:id | One asset + download variants + author/license |
POST /v1/stock/analyze-script | AI: turn a script into b-roll search terms |
POST /v1/stock/import | Copy an asset into the media library (CDN copy) |
See Stock Library for details, and Asset Library License & Terms of Use for the license governing anything you import.
Chat
Send messages to any Kolbo chat model with multi-turn conversation support. Call GET /v1/models?type=chat for the current list of chat model identifiers.
| Endpoint | Description |
|---|---|
POST /v1/chat | Send a chat message (requires polling) |
GET /v1/chat/conversations | List your conversations |
GET /v1/chat/conversations/:id/messages | Get conversation messages |
See Chat for details.
Media Library
Upload local files to the user's Kolbo library, get back a stable CDN URL, and browse everything the user has — uploaded files and AI-generated outputs — with the same filters as the desktop app and Adobe plugin (by project, folder, type, and section).
| Endpoint | Description |
|---|---|
POST /v1/media/upload | Upload a file (multipart) and receive a stable URL |
POST /v1/media/upload-ticket | Mint a short-lived upload-only ticket (token, upload_url, expires_in, max_file_mb) for browser upload flows that cannot hold an API key |
GET /v1/media | List media — filter by project_id, folder_id, type, category (section), source_type, search, sort, include_metadata, pagination (page, page_size). include_deleted=true is the only way to list trashed items; no MCP tool exposes it |
GET /v1/media/:id | Fetch one media item (full metadata) |
DELETE /v1/media/:id | Soft-delete (30-day trash) |
POST /v1/media/:id/restore | Restore from trash |
DELETE /v1/media/:id/permanent | Permanent delete (NOT reversible) |
PATCH /v1/media/:id/project | Move item to a different project |
POST /v1/media/bulk/delete | Bulk soft-delete (≤1000) |
POST /v1/media/bulk/restore | Bulk restore (≤1000) |
POST /v1/media/bulk/permanent | Bulk permanent delete (NOT reversible, ≤1000) |
POST /v1/media/bulk/move | Bulk move to project (atomic, ≤1000) |
GET /v1/media/stats | Item counts + total storage bytes |
POST /v1/media/:id/favorite | Mark a media item as favorited (idempotent) |
DELETE /v1/media/:id/favorite | Remove a media item from favorites (idempotent) |
GET /v1/media/folders | List the user's media folders (owned + shared) |
POST /v1/media/folders | Create a folder |
PUT /v1/media/folders/:id | Rename / recolor / re-icon a folder (owner only) |
DELETE /v1/media/folders/:id | Soft-delete a folder (owner only) |
POST /v1/media/folders/:id/items | Add media items to a folder |
DELETE /v1/media/folders/:id/items | Remove media items from a folder |
POST /v1/media/folders/:id/share | Share a folder by user email (owner only) |
DELETE /v1/media/folders/:id/share/:userId | Revoke folder access (owner only) |
POST /v1/media/folders/:id/move-contents | Move every item in a folder to a project |
See Media Library for the full filter reference and examples.
Presets Discovery
| Endpoint | Description |
|---|---|
GET /v1/presets | List generation presets. Optional type filter: image, video, music, text_to_video (alias of video), or shorts. Omit type and every catalog is returned in one flat presets[], each row tagged with its own type |
Projects
Every generation endpoint accepts an optional project_id body field that routes the generation into a specific project. See Projects.
| Endpoint | Description |
|---|---|
GET /v1/projects | List projects you can write into (owned + shared with edit/full/owner) |
PATCH /v1/sessions/:sessionId/project | Move a session (any type) and all its media to another project |
POST/GET /v1/docs, GET/PUT/DELETE /v1/docs/:id, PATCH /v1/docs/:id/share | AI Docs (Magic Pad): author, edit, and share project-scoped documents |
POST /v1/visual-dna/character-sheet | Generate a multi-angle character sheet for stronger character consistency (credits) |
GET/POST /v1/visual-dna/folders, PUT/DELETE /v1/visual-dna/folders/:folderId, PUT /v1/visual-dna/:id/folder | Visual DNA folders: organize characters (contents move to root on delete) |
POST /v1/projects, PUT /v1/projects/:id, PUT /v1/projects/:id/archive, PUT /v1/projects/:id/unarchive | Project lifecycle: create, rename, archive, unarchive (deletion stays in-app) |
GET /v1/sessions | List sessions across all types (filter by project/type) |
POST /v1/projects/:projectId/context/url, POST /v1/projects/:projectId/context/text, GET /v1/projects/:projectId/context, DELETE /v1/projects/:projectId/context/:fileKey | Project knowledge base (RAG) sources |
GET /v1/projects/:projectId/profile, POST /v1/projects/:projectId/profile/regenerate | Synthesized living project profile |
Custom Chat Agents
Reusable named personas for chat. The agent's description is the system instruction the model adopts.
| Endpoint | Description |
|---|---|
GET /v1/agents | List your agents (personal + global presets) |
POST /v1/agents | Create an agent |
PUT /v1/agents/:id | Update an agent (personal agents only — global presets are protected) |
DELETE /v1/agents/:id | Delete an agent |
See Agents & Sessions for details.
Voices
| Endpoint | Description |
|---|---|
GET /v1/voices | List TTS voices (presets + your cloned voices) |
POST /v1/voices/clone | Clone a voice from an audio sample (multipart; charges credits) |
POST /v1/voices/import-elevenlabs | Import an existing ElevenLabs voice by id |
DELETE /v1/voices/:id | Delete a custom voice |
Video Trim
| Endpoint | Description |
|---|---|
POST /v1/video/trim | Frame-accurate trim of a Kolbo-hosted video — returns a job id |
GET /v1/video/trim/:jobId | Poll the trim job (trim jobs are not on /v1/generate/:id/status) |
See Video Editing and Trim for details.
HTML Artifacts
Publish a self-contained HTML page, SVG, or Mermaid document to a public URL.
This one is not under /api/v1 — it is the app route POST /api/artifact/quick-share, which also accepts X-API-Key. Its fields are camelCase (allowJs, shareToken), not the snake_case used across /v1. See HTML Artifacts.
Other Endpoints
| Endpoint | Description |
|---|---|
GET /v1/models | List available models — the source of truth for identifiers, supported_* constraints, and credit multipliers |
GET /v1/account/credits | Check credit balance |
GET /v1/generate/:id/status | Poll generation status |
POST /v1/generate/:id/cancel | Cancel a running generation and release/refund its reserved credits |
GET /v1/generate/creative-director/:id/status | Poll Creative Director status (per-scene) |
GET /v1/project/lightweight | Lightweight project list (legacy path — prefer GET /v1/projects) |
Reference
Authentication
Create, use, and revoke API keys
Models & Pricing
Model catalog fields, credit costs, and multipliers
Polling & Cancellation
The status contract every async endpoint shares, and how to cancel a run
Credits & Billing
How credits are reserved, charged, and refunded
Errors & Limits
Error codes and per-endpoint rate limits
Skills, Plugin & MCP Setup
Use the same capabilities as native tools in Claude, Cursor, or any MCP app
Build with Lovable, Base44 & More
Ready-to-paste prompts that wire the Kolbo API into AI app builders
Authentication
All requests require the X-API-Key header with your API key:
X-API-Key: YOUR_API_KEYSee Authentication for details on creating and managing keys.
Claude Code Integration
Use Kolbo as native tools in Claude Code via our MCP server. See Claude Code Setup.