Kolbo.AIKolbo.AI Docs
Developer API

Agents & Sessions

Manage reusable custom chat agents, and enumerate every session across all generation types.

Two workspace inventories that sit alongside Projects:

  • Agents — reusable, named personas for the chat tool. An agent's description is the system instruction the model adopts.
  • Sessions — the containers every generation lands in. One endpoint enumerates them across all 17 generation and chat types.

Endpoint

GET    /api/v1/agents
POST   /api/v1/agents
PUT    /api/v1/agents/:id
DELETE /api/v1/agents/:id

GET    /api/v1/sessions
PATCH  /api/v1/sessions/:sessionId/project

Listing Agents

GET /api/v1/agents
ParameterTypeRequiredDescription
searchstringNoCase-insensitive filter on the agent name. Regex-escaped server-side, so user-typed text is safe. Also accepted as query.

Returns your personal agents, any agents scoped to your active organization, and the global preset agents. Sort order is global presets first, then personal agents, then organization agents, newest-first within each group. There is no pagination.

curl "https://api.kolbo.ai/api/v1/agents?search=director" \
  -H "X-API-Key: YOUR_API_KEY"

Response:

{
  "success": true,
  "agents": [
    {
      "id": "66a1c8a2e4b0a3c1d9f5e001",
      "name": "Creative Director",
      "description": "You are a senior creative director. Turn any brief into a structured shot list…",
      "emoji": "🎬",
      "thumbnail": null,
      "is_global": false,
      "file_ids": [],
      "created_at": "2026-07-12T16:38:55.871Z",
      "updated_at": "2026-07-12T16:38:55.871Z"
    }
  ],
  "count": 1
}

is_global: true marks a protected system preset. Presets show up in the list so you can reference them, but they cannot be edited or deleted — both return 403.

Creating an Agent

POST /api/v1/agents
FieldTypeRequiredDescription
namestringNo*Agent name. Omitted → generated from description (falls back to "Custom Agent"). Trimmed server-side.
descriptionstringNo*The persona and instructions — this becomes the system prompt in every conversation that uses the agent. Trimmed; an empty result is stored as null.
emojistringNoEmoji avatar. Omitted or empty → auto-picked from the name and description (falls back to 🤖).
thumbnailstringNoThumbnail image URL.
file_idsarray of stringNoMedia file ObjectIds to attach as the agent's retrieval corpus. Ignored unless it is a JSON array.

* At least one of name / description must be a non-empty string, otherwise 400.

The API route applies no length limit to name or description. The in-app editor validates them at 100 and 2,000 characters respectively, but that validation sits on the web app's own route, not this one. Stay inside those bounds if the user needs to keep editing the agent in the app.

curl -X POST https://api.kolbo.ai/api/v1/agents \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Creative Director",
    "description": "You are a senior creative director. Turn any brief into a structured shot list with camera, lens, and lighting notes."
  }'

The response is { "success": true, "agent": { … } } in the shape shown above. Retrieval embeddings for any attached files are built in the background, so a freshly created agent is usable immediately but its file knowledge lands a moment later.

Your plan's custom-agent cap is enforced — exceeding it returns 403 with { "success": false, "error": "Custom agent limit reached. …" }, or "Custom agent creation not available on your current plan." when the plan allows none. Match on the message, not a code: the SDK error envelope drops the underlying code (CUSTOM_AGENT_LIMIT_EXCEEDED) and data fields on this route.

Agent create / update / delete are limited to 10 requests per minute — the same bucket the video, music, speech, chat, and upload endpoints draw from, so creating agents eats into your generation allowance. Listing is limited to 120 per minute, shared with the whole media-library surface. Both counters are keyed by authenticated user, so several API keys on one account share them. Full bucket map: Errors & Limits.

Agents are created through the API but selected in the app. POST /v1/chat has no field for an agent id — to apply a persona from an API-driven conversation, pass system_prompt on the Chat request instead. Agents you create here are for reuse in the web app's chat tool.

file_ids are MediaFile ObjectIds, and the value is only applied when it is a JSON array — a bare string is silently ignored. Sending it replaces the whole file list rather than appending.

Updating an Agent

PUT /api/v1/agents/:id
FieldTypeRequiredDescription
namestringNoNew name.
descriptionstringNoNew persona/instructions — replaces the old description.
emojistringNoNew emoji avatar.
thumbnailstringNoNew thumbnail URL.
file_idsarray of stringNoReplacement list of media file ObjectIds. Ignored unless it is a JSON array.

At least one of those five fields must be present, otherwise 400. You must own the agent — someone else's agent returns 403, a global preset returns 403, and a missing id returns 404. Fields outside that list are dropped, so is_global, ownership, and organization scope cannot be reassigned through this route.

Retrieval embeddings are rebuilt in the background after every successful update.

Deleting an Agent

DELETE /api/v1/agents/:id

Owner only; global presets are protected.

{ "success": true, "deleted": true, "id": "66a1c8a2e4b0a3c1d9f5e001" }

This is a permanent delete, not a soft delete — the agent record and its retrieval embeddings are removed. Conversations that used the agent are untouched.

Listing Sessions

GET /api/v1/sessions

Enumerates sessions across all generation and chat types, newest activity first.

ParameterTypeRequiredDescription
project_idstringNoRestrict to one project. Must be a valid ObjectId (400 otherwise) and you must be a member (403 otherwise). Also accepted as projectId.
typestringNoOne of the session types below. An unknown value returns 400 listing the valid keys.
pagenumberNo1-indexed. Default 1.
limitnumberNoDefault 20, max 50.
curl "https://api.kolbo.ai/api/v1/sessions?project_id=65f1c8a2e4b0a3c1d9f5e123&type=image&limit=50" \
  -H "X-API-Key: YOUR_API_KEY"

Response:

{
  "success": true,
  "sessions": [
    {
      "session_id": "65f1c8a2e4b0a3c1d9f5e999",
      "name": "API Image Generation - 2026-07-12",
      "type": "image",
      "project_id": "65f1c8a2e4b0a3c1d9f5e123",
      "created_at": "2026-07-12T16:38:55.871Z",
      "updated_at": "2026-07-12T18:02:11.004Z"
    }
  ],
  "pagination": { "page": 1, "limit": 50, "returned": 1, "has_more": false }
}

Scope depends on project_id. With project_id, you get every member's sessions in that shared project, and each row is stamped with owner ({ userId, name, avatar }) plus is_mine. Without it, you get only your own sessions across all projects.

Several session types share one underlying store, so when you do not pass type, a row's type can come back as a pipe-joined string — for example video_from_image|elements|first_last_frame or image_edit|global_image_edit. Match on substring, not equality, when you filter client-side. Passing type always returns that single key. pagination reports returned and has_more rather than a total count.

Session types

The same 17 keys are valid for the type filter here and for the type hint on the move endpoint:

image, video, video_from_image, music, speech, image_edit, sound, creative_director, chat, elements, first_last_frame, lipsync, video_from_video, transcription, global_image_edit, global_video_edit, shorts

3D generations are project-scoped and have no session, so they never appear in this list.

A session's name comes back as null when it was never named, and project_id as null in the rare case a session is not attached to a project.

Moving a Session

PATCH /api/v1/sessions/:sessionId/project relocates a session and all of its media to another project. Full reference: Projects → Moving a Session Between Projects.

MCP Tools

The matching @kolbo/mcp tools are list_agents, create_agent, update_agent, delete_agent, list_sessions, and move_session.

1. list_agents { search: "director" }   -> resolve a name to an agent id
2. list_sessions { project_id }         -> find work that landed in the wrong place
3. move_session  { session_id, project_id }

The MCP create_agent / update_agent tools do not expose file_ids — attach a retrieval corpus through the HTTP API or the web app. create_agent also makes description required (and name optional), which is stricter than the HTTP route, where either one alone is enough.

get_session_usage is not about these sessions. Despite the name, it does not read anything from list_sessions — it aggregates credit spend tagged with the X-Kolbo-Caller-Session-Id header (a per-app-launch id) and returns a total plus per-tool and per-model breakdowns. Only the Kolbo Code desktop app and the sidecar that spawns the MCP set that header, so a plain SDK or MCP caller gets a 400 telling it no caller-session id was forwarded — the tool takes no arguments, so it cannot supply one (the underlying endpoint also accepts a ?caller_session_id= query param, but only records tagged with that id at generation time are counted). It is served by the app API (GET /api/credit-usage/by-caller-session), not by any /api/v1 SDK route. For a plain balance, use GET /api/v1/account/credits — see Credits & Billing.