Media Library
Upload, list, and filter all the media in a user's Kolbo library — by project, folder, type, and section — the same view as the desktop app and Adobe plugin.
The Media Library API exposes the same library the user sees in the Kolbo web app, desktop app, and Adobe plugin. Every uploaded file and every AI-generated output the user has saved is here, with rich filtering by project, folder, type, and section (category).
The base endpoint, GET /api/v1/media, was originally a thin list of uploads. It has been extended with the full filter set used by the desktop app — the older parameters (type, page, pageSize, searchTerm) continue to work exactly as before.
Endpoints
| Endpoint | Description |
|---|---|
POST /v1/media/upload | Upload a file (multipart) and receive a stable Kolbo CDN URL |
GET /v1/media | List media with filters by project, folder, type, section, source, search, and sort |
GET /v1/media/:id | Fetch one media item by id (full metadata) |
DELETE /v1/media/:id | Soft-delete (move to trash, 30-day recovery) |
POST /v1/media/:id/restore | Restore a trashed item |
DELETE /v1/media/:id/permanent | Permanently delete (S3 + DB) — NOT reversible |
PATCH /v1/media/:id/project | Re-assign item to a different project |
POST /v1/media/bulk/delete | Bulk soft-delete (≤1000 ids) |
POST /v1/media/bulk/restore | Bulk restore from trash (≤1000 ids) |
POST /v1/media/bulk/permanent | Bulk permanent delete (≤1000 ids) — NOT reversible |
POST /v1/media/bulk/move | Bulk move to project (≤1000 ids, atomic) |
GET /v1/media/stats | Item counts + total storage bytes (optionally per project) |
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 new folder |
PUT /v1/media/folders/:id | Update folder name / description / color / icon (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 with users by email (owner only) |
DELETE /v1/media/folders/:id/share/:user_id | Revoke a user's access (owner only) |
POST /v1/media/folders/:id/move-contents | Move every item in a folder to a project (owner of items only) |
List Media
The primary discovery endpoint. Returns the user's media — uploaded files and AI-generated outputs they have saved — filtered by any combination of project, folder, type, section, source, and free-text search.
Endpoint
GET /api/v1/mediaQuery Parameters
All parameters are optional. The endpoint defaults to the user's full library, newest first, 50 items per page.
| Parameter | Type | Description |
|---|---|---|
project_id | string (ObjectId) | Restrict to a single project. The user must have access to the project (owner or shared). |
folder_id | string (ObjectId) | Restrict to a user folder. Discover folder IDs via GET /v1/media/folders. Takes precedence over project_id. |
type | string | Media type. One of image, video, audio, all (default). |
category | string | "Section" filter — matches the desktop app sidebar. One of ai, uploaded, edited, favorites, training-lab, all (default). |
source_type | string | Lower-level provenance. One of uploaded, generated, chat-generated. Use category for the common case. |
source | string | Free-form metadata.source tag (e.g. flow for Flow-generated items). |
preset_id | string | Items generated using a specific preset. |
moodboard_id | string | Items generated using a specific moodboard. |
search | string | Free-text match against filename + original prompt. |
sort | string | Order. One of created_desc (default), created_asc, name_asc, name_desc. |
page | integer | 1-indexed page. Default 1. |
page_size | integer | Items per page. Default 50, max 200. |
include_metadata | boolean | Include the full metadata blob on each item. Default false. |
include_deleted | boolean | List only soft-deleted (trashed) items. Default false. |
Section / Category Reference
The category parameter mirrors the section buttons in the Kolbo desktop app and Adobe plugin:
category | Meaning |
|---|---|
ai | Anything AI-generated (text-to-image, video, music, speech, sound, lipsync, etc.) |
uploaded | Files the user uploaded themselves (no AI generation) |
edited | AI-edited variants (e.g. inpainting, image edit outputs) |
favorites | Items the user has starred |
training-lab | Assets created or used inside Training Lab |
all | No category filter (default) |
Examples
List the user's most recent 20 items across everything:
curl "https://api.kolbo.ai/api/v1/media?page_size=20" \
-H "X-API-Key: kolbo_live_..."List all videos in a specific project:
curl "https://api.kolbo.ai/api/v1/media?project_id=6601a1b2c3d4e5f6a7b8c9d0&type=video" \
-H "X-API-Key: kolbo_live_..."List only AI-generated images the user has favorited:
curl "https://api.kolbo.ai/api/v1/media?type=image&category=favorites" \
-H "X-API-Key: kolbo_live_..."List everything in a folder, sorted alphabetically:
curl "https://api.kolbo.ai/api/v1/media?folder_id=6601a1b2c3d4e5f6a7b8c9d0&sort=name_asc" \
-H "X-API-Key: kolbo_live_..."Free-text search across filenames and prompts inside one project:
curl "https://api.kolbo.ai/api/v1/media?project_id=6601...&search=sunset" \
-H "X-API-Key: kolbo_live_..."Response
{
"success": true,
"media": [
{
"id": "660aa1b2c3d4e5f6a7b8c9d0",
"url": "https://cdn.kolbo.ai/u/123/abc.mp4",
"thumbnail_url": "https://cdn.kolbo.ai/u/123/abc-thumb.jpg",
"name": "sunset-beach.mp4",
"filename": "sunset-beach.mp4",
"type": "video",
"media_type": "video",
"category": "generated",
"size": 4823901,
"source_type": "generated",
"generation_type": "text_to_video",
"session_type": "text_to_video",
"prompt": "Cinematic sunset over an empty beach, slow dolly-in",
"width": 1920,
"height": 1080,
"duration": 8,
"is_favorited": true,
"nsfw_detected": false,
"project_id": "6601a1b2c3d4e5f6a7b8c9d0",
"session_id": "6601...",
"user_id": "65f0...",
"user_email": "[email protected]",
"user_name": "You",
"created_at": "2026-05-10T18:24:31.000Z",
"metadata": { "...": "..." }
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total_items": 312,
"total_pages": 7,
"has_next": true
}
}Notes on the response:
categoryis the resolved bucket for the item:generated,uploaded,edited-image, etc. It maps to (but is not identical to) thecategoryquery filter — use the query filter for selection and the responsecategoryfor display.is_favoritedreflects the calling user (relevant for shared projects).- On shared projects, items from other members include
user_email/user_nameso you can attribute them. prompt,width,height,durationare best-effort and may benullfor older items or uploads.
Validation Errors
Invalid enum values return 400:
curl "https://api.kolbo.ai/api/v1/media?type=gif" -H "X-API-Key: ..."
# { "success": false, "error": "Invalid type \"gif\". Allowed: all, image, video, audio." }Get One Media Item
GET /api/v1/media/:idReturns the same shape as items in the list response, plus extended metadata. Works for any item the caller owns or has project access to.
curl "https://api.kolbo.ai/api/v1/media/660aa1b2c3d4e5f6a7b8c9d0" \
-H "X-API-Key: kolbo_live_..."Delete / Restore / Permanently Delete
DELETE /api/v1/media/:id # soft-delete (30-day trash, reversible)
POST /api/v1/media/:id/restore # bring back from trash
DELETE /api/v1/media/:id/permanent # hard-delete (removes from S3 + DB)Soft-delete is the standard "delete" — items move to trash and can be restored for 30 days. After 30 days they are GC'd by the platform automatically.
Permanent delete is not reversible — it removes the MongoDB record, the S3 file, every folder membership, and the source generation record. Use only when the user explicitly asks for unrecoverable deletion.
To list trashed items, use GET /v1/media?include_deleted=true.
# Soft-delete
curl -X DELETE "https://api.kolbo.ai/api/v1/media/660..." \
-H "X-API-Key: kolbo_live_..."
# Restore
curl -X POST "https://api.kolbo.ai/api/v1/media/660.../restore" \
-H "X-API-Key: kolbo_live_..."
# Hard-delete (NOT reversible)
curl -X DELETE "https://api.kolbo.ai/api/v1/media/660.../permanent" \
-H "X-API-Key: kolbo_live_..."Move a Media Item to Another Project
PATCH /api/v1/media/:id/projectCaller must own the item AND have access to the target project.
curl -X PATCH "https://api.kolbo.ai/api/v1/media/660.../project" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "project_id": "6601a1b2c3d4e5f6a7b8c9d0" }'Bulk Operations
All bulk endpoints accept up to 1000 ids per call and require the same access rules as their single-item siblings.
POST /api/v1/media/bulk/delete { media_ids: [...] }
POST /api/v1/media/bulk/restore { media_ids: [...] }
POST /api/v1/media/bulk/permanent { media_ids: [...] } # NOT reversible
POST /api/v1/media/bulk/move { media_ids: [...], project_id: "…" }bulk/move is atomic — if any id in the array isn't owned by the caller, the entire operation is rejected and no items are moved. The other three bulk endpoints silently skip ids not owned by the caller and return both the success count and the not-found count.
curl -X POST "https://api.kolbo.ai/api/v1/media/bulk/delete" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "media_ids": ["660...a", "660...b", "660...c"] }'
# → { "success": true, "deleted_count": 3, "errors": [] }Storage Stats
GET /api/v1/media/stats[?project_id=…]curl "https://api.kolbo.ai/api/v1/media/stats" \
-H "X-API-Key: kolbo_live_..."{
"success": true,
"stats": {
"total": 312,
"images": 178,
"videos": 102,
"audio": 32,
"total_size_bytes": 4823901234
}
}Move Folder Contents to a Project
POST /api/v1/media/folders/:id/move-contentsMoves every item inside the folder to a different project in one call. Caller must own every item in the folder (shared folder members cannot use this) AND have access to the target project.
curl -X POST "https://api.kolbo.ai/api/v1/media/folders/6611.../move-contents" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "project_id": "6601..." }'Favorite a Media Item
Mark or unmark a media item as a favorite for the calling user. Idempotent on both sides: re-favoriting an already-favorited item is a no-op, and unfavoriting a non-favorite is a no-op.
Favorited items show up in GET /v1/media?category=favorites and in the Favorites section of the desktop app and Adobe plugin. is_favorited in the list response reflects the calling user (per-user state, not global).
Access rules:
- The user must own the item or be a member of the item's project.
POST /api/v1/media/:id/favorite
DELETE /api/v1/media/:id/favoritecurl -X POST "https://api.kolbo.ai/api/v1/media/660aa1b2c3d4e5f6a7b8c9d0/favorite" \
-H "X-API-Key: kolbo_live_..."
curl -X DELETE "https://api.kolbo.ai/api/v1/media/660aa1b2c3d4e5f6a7b8c9d0/favorite" \
-H "X-API-Key: kolbo_live_..."{ "success": true, "id": "660aa1b2c3d4e5f6a7b8c9d0", "is_favorited": true }List Media Folders
Folders are user-scoped — they live on the user, not on projects, and can group media across multiple projects.
Endpoint
GET /api/v1/media/foldersReturns folders the user owns plus folders that have been shared with them.
Example
curl "https://api.kolbo.ai/api/v1/media/folders" \
-H "X-API-Key: kolbo_live_..."Response
{
"success": true,
"folders": [
{
"id": "6611...",
"name": "Campaign A — hero shots",
"description": null,
"color": "#3B82F6",
"icon": "folder",
"item_count": 42,
"is_owner": true,
"shared_with_count": 0,
"created_at": "2026-04-01T10:00:00.000Z",
"last_updated": "2026-05-12T08:14:00.000Z"
}
],
"count": 1
}Pass the id of any folder back to GET /v1/media?folder_id=... to list its contents.
Create a Folder
POST /api/v1/media/folders| Body field | Type | Notes |
|---|---|---|
name | string (required) | 1–100 characters |
description | string | up to 500 characters |
color | string | hex #RRGGBB, default #3B82F6 |
icon | string | Lucide icon name (e.g. folder, star, image), default folder |
curl -X POST "https://api.kolbo.ai/api/v1/media/folders" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "name": "Campaign A — hero shots", "color": "#F59E0B", "icon": "star" }'Returns 201 Created with the new folder.
Update a Folder
PUT /api/v1/media/folders/:idOwner only. Any subset of name / description / color / icon may be provided; omitted fields are unchanged. Pass description: "" to clear it.
curl -X PUT "https://api.kolbo.ai/api/v1/media/folders/6611.../" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "name": "Campaign A — final", "color": "#10B981" }'Delete a Folder
DELETE /api/v1/media/folders/:idOwner only. The folder is soft-deleted and item membership is cleared, but the items themselves remain in the user's media library.
curl -X DELETE "https://api.kolbo.ai/api/v1/media/folders/6611..." \
-H "X-API-Key: kolbo_live_..."Add Items to a Folder
POST /api/v1/media/folders/:id/itemsCaller must own the folder or be a shared member. Idempotent — items already in the folder are skipped. Up to 500 items per call.
curl -X POST "https://api.kolbo.ai/api/v1/media/folders/6611.../items" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "media_ids": ["660...a", "660...b", "660...c"] }'{ "success": true, "folder_id": "6611...", "added": 3, "skipped": 0 }Remove Items from a Folder
DELETE /api/v1/media/folders/:id/itemsBody shape is identical to add. Items remain in the user's library — only the folder membership is removed.
curl -X DELETE "https://api.kolbo.ai/api/v1/media/folders/6611.../items" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "media_ids": ["660...a"] }'Share a Folder
POST /api/v1/media/folders/:id/shareOwner only. Pass a list of user emails; the server resolves them to user ids. Emails that don't match a Kolbo account come back in not_found (no error — the rest still succeed). Up to 50 emails per call.
Shared members can list folder contents, add and remove items, but cannot delete the folder, update its metadata, or reshare it.
curl -X POST "https://api.kolbo.ai/api/v1/media/folders/6611.../share" \
-H "X-API-Key: kolbo_live_..." \
-H "Content-Type: application/json" \
-d '{ "user_emails": ["[email protected]", "[email protected]"] }'{
"success": true,
"folder": { "id": "6611...", "shared_with": ["65f1...", "65f2..."], "shared_with_count": 2, "...": "..." },
"shared_with_user_ids": ["65f1...", "65f2..."],
"not_found": []
}Revoke Folder Access
DELETE /api/v1/media/folders/:id/share/:user_idOwner only. The user's id is the one returned in the folder's shared_with array (or shared_with_user_ids from the share response).
curl -X DELETE "https://api.kolbo.ai/api/v1/media/folders/6611.../share/65f1..." \
-H "X-API-Key: kolbo_live_..."Upload Media
POST /api/v1/media/uploadMultipart form upload. Re-hosts the file on Kolbo CDN and registers it in the user's library so you can reuse the URL in any subsequent generation call.
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to upload (image, video, audio, or document). |
description | string | No | Description / caption for the uploaded media. |
project_id | string | No | Project to file the upload into (needs edit+ permission — see Projects). Omitted → the upload is not scoped to a project. |
curl -X POST https://api.kolbo.ai/api/v1/media/upload \
-H "X-API-Key: kolbo_live_..." \
-F "file=@/path/to/photo.jpg" \
-F "description=Reference photo for the campaign" \
-F "project_id=65f1c8a2e4b0a3c1d9f5e123"JavaScript Example
const API_KEY = "kolbo_live_YOUR_API_KEY";
const BASE = "https://api.kolbo.ai/api";
async function main() {
// 1. Discover the user's folders
const fRes = await fetch(`${BASE}/v1/media/folders`, {
headers: { "X-API-Key": API_KEY }
});
const { folders } = await fRes.json();
console.log(`User has ${folders.length} folders.`);
// 2. List AI-generated videos from a specific project, newest first
const params = new URLSearchParams({
project_id: "6601a1b2c3d4e5f6a7b8c9d0",
type: "video",
category: "ai",
sort: "created_desc",
page_size: "50"
});
const mRes = await fetch(`${BASE}/v1/media?${params}`, {
headers: { "X-API-Key": API_KEY }
});
const { media, pagination } = await mRes.json();
console.log(`Got ${media.length} of ${pagination.total_items} videos`);
for (const item of media) {
console.log(item.name, "→", item.url);
}
}
main();Python Example
import requests
API_KEY = "kolbo_live_YOUR_API_KEY"
BASE = "https://api.kolbo.ai/api"
HEADERS = {"X-API-Key": API_KEY}
# 1. List the user's favorite images across all projects
res = requests.get(
f"{BASE}/v1/media",
headers=HEADERS,
params={
"type": "image",
"category": "favorites",
"page_size": 100,
},
)
data = res.json()
for item in data["media"]:
print(item["name"], "→", item["url"])
# 2. Pagination
while data["pagination"]["has_next"]:
next_page = data["pagination"]["page"] + 1
res = requests.get(
f"{BASE}/v1/media",
headers=HEADERS,
params={
"type": "image",
"category": "favorites",
"page_size": 100,
"page": next_page,
},
)
data = res.json()
for item in data["media"]:
print(item["name"], "→", item["url"])Tips
- For shared projects, the response includes items from all members. Use
user_id/user_emailto attribute.is_favoritedalways reflects the calling user. - Combine
project_id+category=ai+type=videoto grab every AI-generated video clip from a campaign in one call — useful for batch downloads or stitching. folder_idalways wins overproject_idwhen both are set. Folders are cross-project by design.page_sizeis capped at200. For larger exports, paginate withhas_next.searchis escaped and safe to pass user-typed text directly.- The legacy parameters (
pageSizecamelCase,searchTerm) are still accepted alongside the new snake_case names.