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
These examples use the existing credit-billed API. Building with the separate USD wallet? Start with USD Console Quick Start. The key types and balances are not interchangeable.
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, body { status: true, data: { id, keyPrefix, name, permissions, createdAt, expiresAt }, fullKey, message }). Besides the required name (non-empty string), 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). Key management needs an interactive sign-in: calling these routes with an X-API-Key instead of a JWT returns 403 INTERACTIVE_AUTH_REQUIRED. Key creation is limited to 10 attempts per hour per user. If you lose the key you can re-reveal it with GET /api/api-keys/:keyId/reveal (same JWT auth, 30 requests/minute) 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, chat, 3D); transcription always echoes "auto", and Creative Director echoes the model you sent or "smart_select". Video-to-video has no Smart Select: omitting model there returns 400 MODEL_REQUIRED. POST /v1/generate/music, /v1/generate/speech, and /v1/generate/sound instead substitute a concrete default identifier for that type and echo it (suno-v6, eleven_v4, and elevenlabs-sound-effects-v1 respectively; suno-v5.5 on /v1/generate/music/extend and /cover; music-v1 when the music body carries composition_plan, and on /v1/generate/music/edit-section). POST /v1/edit/image and POST /v1/edit/video echo the engine the edit resolved, falling back to the model you sent, or null.
An explicit model the catalog does not know is rejected with 400 MODEL_NOT_FOUND before the job starts. The message names near matches (Did you mean: …?) and points you to GET /v1/models?type=…. Canonical identifiers, registered aliases and provider-prefixed forms are accepted; a display name is not an identifier. Only an omitted, blank or auto-alias model gets the default described above. Video-to-video handles unknown identifiers itself: they are passed to its generation controller, which rejects them with its own error. Get valid identifiers from GET /v1/models.
credits_charged is the up-front estimate (it can be null); the real spend arrives on the status response. poll_interval_hint is seconds: 2 for chat, 3 for /v1/generate/image and /v1/generate/image-edit, 5 for sound and Creative Director, 8 for everything else (including /v1/edit/image). 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 }
],
"session_id": "68f...",
"project_id": "68e..."
}state is one of processing, completed, failed, or cancelled. 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), plus result.model_name when a display name was recorded. credits_used / credits_breakdown ([{ model, amount }]) are the real multiplier-adjusted spend; they appear only once state === "completed", and only when a charge was recorded for the generation. On state === "failed" you get error (a string) plus a structured failure object with message, category, code, retryable, and severity — 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 and per code path — the SDK passes through whatever the underlying generation handler answers, so 200, 201, and 202 Accepted are all in use (video trim, for example, answers 202), 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, when a job started but its id could not be tracked) returns a 2xx with success: false, and errors from the global middleware and rate limiters 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 polled generation endpoint, message_id on POST /v1/chat, and jobId on video trim. The audio separation routes (/v1/audio/*) answer inline with their result and return no job handle. 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 (the first output, when the generation produced several). 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 started = await res.json();
if (!res.ok || started.success === false || started.status === false) {
throw new Error(started.error ?? started.message ?? `HTTP ${res.status}`);
}
const { generation_id } = started;
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"}
)
started = res.json()
if not res.ok or started.get("success") is False or started.get("status") is False:
raise Exception(started.get("error") or started.get("message") or f"HTTP {res.status_code}")
generation_id = started["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, with two exceptions. Audio Separation runs inline: the request stays open until the stems are ready and the response carries the result, with nothing to poll. Video Trim 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, and the generationId field, which is the same trim job id, not a generation id). 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 |
| Music extend / cover (from existing audio) | POST /v1/generate/music/extend, POST /v1/generate/music/cover (source via upload_id from POST /v1/generate/music/import, or audio_url) | Music Generation |
| Music section edit (structured-song tracks) | POST /v1/generate/music/edit-section | 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 |
| Audio Separation (Dialogue / Music / Effects stems) — inline, no polling | POST /v1/audio/separate (+ /clean-dialogue, /ambience) | Audio Separation |
| Video Trim | POST /v1/video/trim | Video Editing |
Rate limits differ by endpoint. Limits are per user account per minute (keys of the same account share them), and a request that fails does not count against the window.
- Image endpoints (
/v1/generate/image,/v1/generate/image-edit,/v1/edit/image): 30/minute, in their own bucket. - Every other generation write (video, music including import/extend/cover/reference-audio/edit-section, speech, sound, elements, first-last-frame, lipsync, video-to-video, 3D, Creative Director, chat, video analysis,
/v1/edit/video, video trim, cancel, media upload, voice clone/import, Visual DNA create/update, character sheet, skill create/update/delete, lipsync-plan writes): 30/minute, shared. /v1/transcribe: 100/minute.- Media library, folders, sessions, AI Docs, Review, moodboards and color palettes: 120/minute; bulk media and session move/split/undo routes: 20/minute.
- Audio separation (
/v1/audio/separate,/clean-dialogue,/ambience): 10/minute. - Video Editor session create and export, URL download start, and the two paid Music Library acquisition routes: 5/minute each.
A 429 carries limit, window_seconds, and retryAfter (seconds). See Errors & Limits.
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 |
PUT /v1/visual-dna/:id | Update a Visual DNA in place (name, description, stills, sheet) |
DELETE /v1/visual-dna/:id | Delete a Visual DNA |
POST /v1/visual-dna/:id/import | Copy a global preset (no body) or a collaborator's Visual DNA (body project_id, required for collaborator imports) into your own library. Free |
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 (image files sent as multipart are capped at 15 per request, 10 MB each, images only). Pass moodboard_id to image generation, image editing, or Creative Director requests (Creative Director also accepts several as moodboard_ids). See Moodboards for details.
Color DNA
A saved color palette that, once active, color-grades your generations automatically. Color DNA is account-wide: one palette at a time is the account's active palette, and it stays on until you deactivate it or activate another. A project is never required; passing one only records where the palette was born (which shares it with that project's edit/full members) and points the project's showcase at it.
| Endpoint | Description |
|---|---|
GET /v1/color-palettes | List your palettes (personal + active-organization scope, plus palettes born in the project you name). Query: page (default 1), limit (default 50, clamped to 1–100), projectId or project_id (optional). Response: color_palettes[], presets[] (system Color DNAs, not paginated), pagination. is_active marks the account's active palette |
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 — the new palette becomes the account's active palette unless you send false), projectId / project_id (string, optional), shareWithOrganization (bool, optional, opt-in). Any other body key is rejected with 400 |
PUT /v1/color-palettes/:id | Rename and/or replace colors / source_image_urls (owner only, never changes which palette is active). Any other body key is rejected with 400 |
DELETE /v1/color-palettes/:id | Delete a palette you own; if it was active, Color DNA turns off, and it is cleared from every project that pointed at it |
POST /v1/color-palettes/:id/activate | Make this the account's active palette. Body: projectId / project_id (optional — only also points that project's showcase at it, when you can edit the project) |
POST /v1/color-palettes/deactivate | Turn Color DNA off for the account. No body needed (projectId is ignored) |
POST /v1/color-palettes/analyze | Extract colors from 1–5 image URLs. Body: image_urls (array, required, 1–5). Free, saves nothing, and has an extra limit of 10 requests/minute |
skip_color_palette: true opts one request out of the active palette without deactivating 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 wraps the grouped map in a dimensions object — { success: true, dimensions: { "<dimension>": [{ id, name, description, thumbnail_url, preview_url?, ui_hint?, sort_order, bundle? }, …] } } — and sets no ETag (an environment without the catalog returns an empty dimensions). The dimension keys are data-driven (the catalog can serve looks, camera, lens, focal_length, aperture, angle, shot_type, lighting, color_palette, genre, tempo, 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, keyed by dimension. looks entries are combo recipes, not a dimension you pass: expand a look's bundle ({ <dimension>: <preset id> }) into the cinematic object instead. 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 | 128/320/WAV URLs — watermarked previews unless the account has clean access (a subscription that includes it, or a prior purchase of this track) |
GET /v1/music-library/track/:id/related | Stems + alternate versions, gated the same way |
GET /v1/music-library/track/:id/lyrics | Lyrics text + theme + explicit flag |
POST /v1/music-library/clean/:trackId | Paid — acquire a clean, unwatermarked MP3/WAV. Body: requestId (required, 8–80 chars of A-Z a-z 0-9 _ -), format (mp3 default | wav), optional stem (a stem ref from /related), purpose (download | timeline), projectId |
POST /v1/music-library/import | Paid — acquire a clean file and copy it into the media library. Body: trackId (required), format (mp3 | wav), optional requestId, projectId |
The two acquisition endpoints charge on the first call (accounts without clean access buy the track with credits), with no confirmation step, and require a write-enabled API key — a read-only key gets 403 API_KEY_READ_ONLY. They are idempotent through the requestId you supply, so send a stable one when retrying; on /import an omitted requestId is generated server-side, but a track already in your media library is returned as-is (alreadyImported: true) instead of being bought again. Both share a 5/minute rate limit, much tighter than the 60/minute 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 field file, up to 500 MB) and receive a stable URL. A source_url body is rejected with 400 — fetch the bytes yourself and send them as the file |
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, session_id / session_ids, preset_id, moodboard_id, type (all | image | video | audio), category (section: all | ai | uploaded | edited | favorites | training-lab), source_type, source, search, sort, include_metadata, pagination (page, page_size — capped at 200). An unknown type / category / source_type / sort value is a 400. 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 (partial success, ≤500) |
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 as { success, presets[], count }. Optional type filter: image, image_edit (a separate catalog — its ids are the valid preset_id values for /v1/generate/image-edit and are not interchangeable with image ids), video, music, or text_to_video (alias of video). Omit type and every catalog is returned in one flat presets[], each row tagged with its own type (video presets then appear twice, once as video and once as text_to_video). An unrecognized type returns an empty list, not an error. |
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). Query: page (default 1), limit (1–200, default 50), include_archived=true. is_default: true marks the "API Generations" fallback project |
PATCH /v1/sessions/:sessionId/project | Move a session (any type) with all its generations and media to another project |
POST /v1/sessions/move | Move up to 100 sessions into one project in a single call |
GET /v1/sessions/:sessionId/generations | List a session's generations as groups (prompt + all its outputs) |
POST /v1/sessions/:sessionId/generations/move | Move selected generations into another existing session |
POST /v1/sessions/:sessionId/split | Split selected generations into a new session |
POST /v1/sessions/organize/undo/:operationId | Undo a move or split (15-minute window) |
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 |
GET/POST /v1/review/* (assets, collections, comments, share-links) | Kolbo Review: Frame.io-style client review — versions, status, comments, guest links |
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, GET /v1/projects/:id, PUT /v1/projects/:id, PUT /v1/projects/:id/archive, PUT /v1/projects/:id/unarchive | Project lifecycle: create, read (full description), rename/describe, archive, unarchive (deletion stays in-app) |
POST /v1/projects/:projectId/duplicate | Duplicate a project you own |
POST /v1/projects/:id/transfer, GET /v1/project-transfers, POST /v1/project-transfers/:id/accept, POST /v1/project-transfers/:id/decline, DELETE /v1/project-transfers/:id | Transfer project ownership to another user, and accept / decline / cancel pending transfers |
GET /v1/sessions | List sessions across all types (filter by project/type) |
PATCH /v1/sessions/:sessionId, DELETE /v1/sessions/:sessionId, POST /v1/sessions/:sessionId/restore | Rename, soft-delete, and restore a session |
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 |
GET /v1/projects/:projectId/assets, POST .../assets/link, PUT .../assets/:type/:id/note, DELETE .../assets/:type/:id | Project cast: list / tag / untag Visual DNAs and moodboards; per-asset purpose notes |
Skills (Custom Chat Agents)
Reusable named personas for chat. The skill's description is the system instruction the model adopts. Every route exists under both /v1/skills (current name) and /v1/agents (original path, kept working) with identical behavior.
| Endpoint | Description |
|---|---|
GET /v1/skills (or /v1/agents) | List your skills (personal + global presets) |
POST /v1/skills (or /v1/agents) | Create a skill |
PUT /v1/skills/:id (or /v1/agents/:id) | Update a skill (personal skills only — global presets are protected) |
DELETE /v1/skills/:id (or /v1/agents/:id) | Delete a skill |
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 body with voiceName (required) and file fields audioFile, optional promptAudioFile and avatarFile, 25 MB each; 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. Body: video_url (required), start_time and end_time (required, numbers in seconds — strings are a 400), project_id (optional). Returns 202 with 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.
Personal Fonts
Upload OTF, TTF, or WOFF2 files to your font library, then pass family ids as font_ids on image creation, image editing, or image-mode Creative Director.
| Endpoint | Description |
|---|---|
GET /v1/fonts | List / search fonts (source=custom | global | all) |
POST /v1/fonts | Upload one font file (multipart field file) |
GET /v1/fonts/uploads/:id | Poll upload processing status |
POST /v1/fonts/upload-tickets | Mint a one-use upload ticket for remote or browser uploads |
GET /v1/fonts/:id | Inspect a family, its styles and scripts |
PATCH /v1/fonts/:id | Rename a family |
DELETE /v1/fonts/:id | Delete a family |
See Personal Fonts.
Video Analysis, Video Editor and Downloads
| Endpoint | Description |
|---|---|
POST /v1/analyze/video | Ask questions about a video by URL. Answers inline (no polling), token-billed. See Video Analysis |
GET /v1/editor/schema, GET /v1/editor/sessions, GET /v1/editor/sessions/:session_id, POST /v1/editor/sessions, PATCH /v1/editor/sessions, POST /v1/editor/exports | Build editable timelines from existing media and export them to MP4. Create and export are limited to 5/minute. See Video Editor API |
POST /v1/downloads, GET /v1/downloads/:jobId, DELETE /v1/downloads/:jobId | Download media from a public page URL into your library as a server job (start, poll, cancel). Start and cancel need a write-enabled key; start is limited to 5/minute |
Other Endpoints
| Endpoint | Description |
|---|---|
GET /v1/models | List available models — the source of truth for identifiers, supported_* constraints, and credit multipliers. Query: type, provider |
GET /v1/account/credits | Check credit balance |
GET /v1/account/plans | Read-only plan and credit-pack catalog (purchases stay on app.kolbo.ai) |
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) |
POST /v1/generate/music/composition-plan | Free: turn a prompt into an editable structured-song plan for composition_plan (nothing is generated or charged) |
POST /v1/generate/music/reference-audio | Billed: register a media-library audio item (media_id) as a structured-song reference; returns a song_id |
/v1/lipsync-plans/:sessionId/* | Build, prepare, and quote performance plans for plan-driven lipsync models. See Elements: Performance plans |
/v1/flows/* | Read, edit, estimate, and run Flow Builder canvases. See Flow Builder |
/v1/trends/*, /v1/recast-presets/* | Run trend recipes, Motion Library presets, and catalog styles; browse the Motion Library. See Trends |
/v1/morphious-styles/* | Morphious look catalog and custom styles. See Morphious Styles |
/v1/blender/*, /v1/adobe/*, /v1/resolve/* | Bridges to connected Blender, Adobe (Premiere Pro / After Effects), and DaVinci Resolve sessions. See Blender, Adobe & Resolve Bridges |
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.