Kolbo.AIKolbo.AI Docs
Developer API

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

EndpointDescription
POST /v1/media/uploadUpload a file (multipart) and receive a stable Kolbo CDN URL
GET /v1/mediaList media with filters by project, folder, type, section, source, search, and sort
GET /v1/media/:idFetch one media item by id (full metadata)
DELETE /v1/media/:idSoft-delete (move to trash, 30-day recovery)
POST /v1/media/:id/restoreRestore a trashed item
DELETE /v1/media/:id/permanentPermanently delete (S3 + DB) — NOT reversible
PATCH /v1/media/:id/projectRe-assign item to a different project
POST /v1/media/bulk/deleteBulk soft-delete (≤1000 ids)
POST /v1/media/bulk/restoreBulk restore from trash (≤1000 ids)
POST /v1/media/bulk/permanentBulk permanent delete (≤1000 ids) — NOT reversible
POST /v1/media/bulk/moveBulk move to project (≤1000 ids, atomic)
GET /v1/media/statsItem counts + total storage bytes (optionally per project)
POST /v1/media/:id/favoriteMark a media item as favorited (idempotent)
DELETE /v1/media/:id/favoriteRemove a media item from favorites (idempotent)
GET /v1/media/foldersList the user's media folders (owned + shared)
POST /v1/media/foldersCreate a new folder
PUT /v1/media/folders/:idUpdate folder name / description / color / icon (owner only)
DELETE /v1/media/folders/:idSoft-delete a folder (owner only)
POST /v1/media/folders/:id/itemsAdd media items to a folder
DELETE /v1/media/folders/:id/itemsRemove media items from a folder
POST /v1/media/folders/:id/shareShare a folder with users by email (owner only)
DELETE /v1/media/folders/:id/share/:user_idRevoke a user's access (owner only)
POST /v1/media/folders/:id/move-contentsMove 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/media

Query Parameters

All parameters are optional. The endpoint defaults to the user's full library, newest first, 50 items per page.

ParameterTypeDescription
project_idstring (ObjectId)Restrict to a single project. The user must have access to the project (owner or shared).
folder_idstring (ObjectId)Restrict to a user folder. Discover folder IDs via GET /v1/media/folders. Takes precedence over project_id.
typestringMedia type. One of image, video, audio, all (default).
categorystring"Section" filter — matches the desktop app sidebar. One of ai, uploaded, edited, favorites, training-lab, all (default).
source_typestringLower-level provenance. One of uploaded, generated, chat-generated. Use category for the common case.
sourcestringFree-form metadata.source tag (e.g. flow for Flow-generated items).
preset_idstringItems generated using a specific preset.
moodboard_idstringItems generated using a specific moodboard.
searchstringFree-text match against filename + original prompt.
sortstringOrder. One of created_desc (default), created_asc, name_asc, name_desc.
pageinteger1-indexed page. Default 1.
page_sizeintegerItems per page. Default 50, max 200.
include_metadatabooleanInclude the full metadata blob on each item. Default false.
include_deletedbooleanList 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:

categoryMeaning
aiAnything AI-generated (text-to-image, video, music, speech, sound, lipsync, etc.)
uploadedFiles the user uploaded themselves (no AI generation)
editedAI-edited variants (e.g. inpainting, image edit outputs)
favoritesItems the user has starred
training-labAssets created or used inside Training Lab
allNo 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:

  • category is the resolved bucket for the item: generated, uploaded, edited-image, etc. It maps to (but is not identical to) the category query filter — use the query filter for selection and the response category for display.
  • is_favorited reflects the calling user (relevant for shared projects).
  • On shared projects, items from other members include user_email / user_name so you can attribute them.
  • prompt, width, height, duration are best-effort and may be null for 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/:id

Returns 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/project

Caller 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-contents

Moves 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/favorite
curl -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/folders

Returns 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 fieldTypeNotes
namestring (required)1–100 characters
descriptionstringup to 500 characters
colorstringhex #RRGGBB, default #3B82F6
iconstringLucide 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/:id

Owner 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/:id

Owner 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/items

Caller 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/items

Body 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/share

Owner 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_id

Owner 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/upload

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

FieldTypeRequiredDescription
filefileYesThe file to upload (image, video, audio, or document).
descriptionstringNoDescription / caption for the uploaded media.
project_idstringNoProject 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_email to attribute. is_favorited always reflects the calling user.
  • Combine project_id + category=ai + type=video to grab every AI-generated video clip from a campaign in one call — useful for batch downloads or stitching.
  • folder_id always wins over project_id when both are set. Folders are cross-project by design.
  • page_size is capped at 200. For larger exports, paginate with has_next.
  • search is escaped and safe to pass user-typed text directly.
  • The legacy parameters (pageSize camelCase, searchTerm) are still accepted alongside the new snake_case names.