Chat & sessions
SSE streaming chat, follow-up suggestions, session CRUD, message history, search, export, and categories under /api/chat and /api/sessions.
This page is the contract reference for the chat surface: streaming a chat turn, managing sessions, reading message history, and organizing chats into categories. The two streaming endpoints return Server-Sent Events; everything else is plain JSON.
Base URL: https://api.cognitivx.io. Chat endpoints are mounted under
/api/chat; sessions and categories under /api/sessions. Every endpoint
requires auth: pass Authorization: Bearer <key> (a JWT from
POST /api/auth/signin, or an API key created at
developers.cognitivx.io/keys) or the
X-API-Key: <key> header. An optional X-Org-ID: <id> header scopes the
request to an organization. All ids are UUID strings and timestamps are
ISO-8601.
Sessions are owned per user. A session you do not own returns 404, never a
403, so the API never leaks whether an id exists. The history endpoint is the
one exception: it returns an empty list for an unknown or unowned session.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /api/chat/stream | Stream a chat turn (SSE) |
POST | /api/chat/regenerate | Regenerate the last assistant message (SSE) |
POST | /api/chat/suggest | Suggest up to 3 follow-up prompts |
GET | /api/sessions | List sessions (keyset pagination) |
POST | /api/sessions | Create a session |
GET | /api/sessions/{session_id} | Get one session |
PATCH | /api/sessions/{session_id} | Rename a session |
DELETE | /api/sessions/{session_id} | Delete a session and its messages |
GET | /api/sessions/{session_id}/messages | Get full message history |
DELETE | /api/sessions/{session_id}/messages/{message_id} | Delete one message |
GET | /api/sessions/search | Search message content across sessions |
GET | /api/sessions/export | Export all sessions as JSON or Markdown |
PUT | /api/sessions/{session_id}/move | Move a session to a category |
PUT | /api/sessions/{session_id}/pin | Toggle pinned |
PUT | /api/sessions/{session_id}/archive | Toggle archived |
POST | /api/sessions/{session_id}/promote-to-circle | Convert a session into a Circle |
POST | /api/sessions/categories | Create a category |
GET | /api/sessions/categories | List categories |
PATCH | /api/sessions/categories/{category_id} | Update a category |
DELETE | /api/sessions/categories/{category_id} | Delete a category |
PUT | /api/sessions/categories/reorder | Reorder categories |
Error responses are { "detail": "<message>" } with a 4xx/5xx status, except
that once a stream has started (HTTP 200), failures are delivered in-band as
SSE events rather than HTTP errors. See Streaming errors.
The TypeScript SDK (@cognitivx/sdk) does not wrap the streaming endpoints.
There is no chat namespace and no client class. Call /api/chat/stream and
/api/chat/regenerate over raw HTTP and parse the SSE stream yourself, as shown
below. The JSON endpoints on this page can be called with apiClient or plain
fetch.
Stream a chat turn
Send one user message in a session and stream iCog's reply token by token over Server-Sent Events. The server recalls relevant memories, streams the reply, persists both the user and assistant messages, and (in the background) extracts new memories and auto-titles new sessions.
POST /api/chat/stream · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
Request body (ChatRequest):
| Field | Type | Required | Description |
|---|---|---|---|
message | string | yes | The user's message text. |
session_id | string (UUID) | yes | Target session. Must be owned by the caller. |
provider | string | no | LLM provider hint. Default "openrouter". Advisory only: iCog routes the actual model internally by message complexity and budget. |
file_ids | string[] | no | Ids of previously uploaded files to attach. Default []. |
content_blocks | object[] | no | Multimodal blocks. Each: { type: string (required), text?: string, file_id?: string, filename?: string }. Default []. |
tools | string[] | no | Names of connector tools to expose to the model this turn. Default []. |
url_snapshot_hash | string | null | no | Hash of a captured URL snapshot to analyze against memory. |
deep | boolean | no | Request deep multi-hop recall. Default false. |
depth | "quick" | "deep" | "sage" | null | no | Recall/answer depth tier. Silently clamped to the caller's plan limit. |
existing_reflex_id | string | null | no | When set, enters reflex edit mode for that reflex (must be owned, else 403). |
geo_lat | number | null | no | Caller latitude for location-aware answers. |
geo_lon | number | null | no | Caller longitude. |
curl -N https://api.cognitivx.io/api/chat/stream \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "What did we decide about the auth migration?",
"session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d"
}'The SDK does not stream chat. Call the endpoint with fetch and parse the
line-delimited SSE envelopes yourself. Concatenate only the data of
type: "token" events into your UI.
const res = await fetch('https://api.cognitivx.io/api/chat/stream', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.COGNITIVX_API_KEY}`,
'Content-Type': 'application/json',
Accept: 'text/event-stream',
},
body: JSON.stringify({
message: 'What did we decide about the auth migration?',
session_id: '5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d',
}),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
let buffer = '';
let reply = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// Events are separated by a blank line; each line starts with "data: ".
const events = buffer.split('\n\n');
buffer = events.pop() ?? '';
for (const event of events) {
const line = event.split('\n').find((l) => l.startsWith('data: '));
if (!line) continue;
const evt = JSON.parse(line.slice(6)); // { type, data }
if (evt.type === 'token') reply += evt.data;
if (evt.type === 'done') console.log('message_id:', evt.message_id);
}
}Response
Content-Type: text/event-stream. Each event is one line, data: <json>\n\n,
where <json> is an envelope { "type": <string>, "data": <any> }. A typical
ordered sequence:
data: {"type": "thinking", "data": true}
data: {"type": "recall.start", "data": {"recall_id": "a1b2c3d4", "mode": "deep", "credit_cost": 10, "expected_latency_ms": 2500}}
data: {"type": "memory_chain", "data": {"kind": "search", "query": "auth migration", "hits": 3, "total_unique": 7}}
data: {"type": "recall.complete", "data": {"recall_id": "a1b2c3d4", "actual_latency_ms": 2210, "result_count": 12}}
data: {"type": "token", "data": "You "}
data: {"type": "token", "data": "decided "}
data: {"type": "metadata", "data": {"input_tokens": 1840, "output_tokens": 96, "model": "openai/gpt-oss-120b", "provider": "openrouter"}}
data: {"type": "confidence", "data": {"memory_count": 12, "scored_count": 5, "mean_confidence": 0.83, "min_confidence": 0.41, "low_confidence_ratio": 0.2}}
data: {"type": "done", "data": true, "message_id": "7c1e9a02-3b4d-4f6a-8c2e-9d0b1a2c3e4f"}done.message_id is the persisted assistant message UUID. It is null for
short-circuit turns (for example reflex-creation cards or reflex edit mode).
Behind Cloudflare the server sets X-Accel-Buffering: no and
Cache-Control: no-cache so events flush immediately. Do not buffer the whole
body, and use SSE (an EventSource-style reader), not WebSockets. The 200
response also carries quota headers (used / limit / remaining).
Event types
The type field on the envelope can be any of the following. The only one you
concatenate for prose is token; treat the rest as structured side-channel data
and render or ignore them as you see fit.
| Event | data shape / meaning |
|---|---|
thinking | boolean. The model is working. |
token | string delta. Append these for the reply text. |
metadata | Per-LLM-round usage: input_tokens, output_tokens, model, provider. Adds cost_usd only on the PAYG tier. |
recall.start / recall.complete | Recall lifecycle, with recall_id and latency. |
memory_chain, deep_plan, deep_search, deep_reflect, deep_synthesize | Recall progress, including deep multi-hop steps. |
confidence | Aggregate confidence over the recalled memories. |
model_downgrade, credit_estimate | Routing/budget notices. |
web_search, places, image | Tool/result surfaces. |
ui_block, text_block, reasoning | Rich content blocks (for example charts or tables from a spreadsheet, or reflex-creation cards). |
tool_call_start, tool_call_result, tool_confirm | Connector tool loop. |
url_suggestions, url_auto_learned, url_resurface, research_intent, insight_card | Proactive and research surfaces. |
error, credits_exhausted | In-band failures (see below). |
done | Terminal event. Always sent. Carries message_id. |
Errors
Before the stream starts, normal HTTP errors apply:
401— missing or invalid key.403—existing_reflex_idbelongs to another user (detail: "forbidden").404—session_idnot owned by the caller ("Session not found").422—messageorsession_idmissing or malformed.503—"LLM Router not initialized".
Once the stream has started (HTTP 200), failures are delivered in-band as
events, not as HTTP errors:
data: {"type": "error", "data": "<message>"}
data: {"type": "credits_exhausted", "data": {"current_tier": "free", "cap_reset_at": "2026-07-01T00:00:00Z", "upgrade": {...}}}credits_exhausted fires when monthly recall credits run out and includes the
current tier, the cap reset time, and upgrade/top-up options. In both cases you
still receive a terminal done event, so always wait for it.
Regenerate the last assistant message
Delete the last assistant message in a session and re-stream a fresh reply. Same
SSE contract as /api/chat/stream. If message is empty,
the server reuses the last user message in the session as the prompt. The
trailing assistant row is only deleted when the last message's role is actually
assistant.
POST /api/chat/regenerate · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
Body is the same ChatRequest as /api/chat/stream. message may be "" to
regenerate against the existing last user message; session_id is still
required.
curl -N https://api.cognitivx.io/api/chat/regenerate \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{"message": "", "session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d"}'The response is an identical SSE stream, ending with a done event whose
message_id is the new assistant message UUID.
Errors: same as /api/chat/stream (401, 404 "Session not found",
422, 503), plus in-band error / credits_exhausted events once streaming
begins.
Suggest follow-up prompts
Return up to 3 short suggested next prompts based on the last assistant message. Non-streaming JSON.
POST /api/chat/suggest · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
Request body (SuggestRequest):
| Field | Type | Required | Description |
|---|---|---|---|
last_message | string | yes | The last assistant message text. Truncated server-side to 1000 chars. |
session_id | string | yes | The session the suggestions are for. |
curl https://api.cognitivx.io/api/chat/suggest \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"last_message": "The auth migration moved sessions to JWT...",
"session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d"
}'{
"suggestions": [
"Show me the migration diff",
"What broke for existing users?",
"How do we roll back?"
]
}Each suggestion is capped under 40 chars and the list is trimmed to at most 3 strings.
Errors: 401 invalid key. 422 missing last_message/session_id. 503
"LLM Router not initialized". On any generation or parse failure the endpoint
returns 200 with { "suggestions": [] }, so it never errors mid-suggest.
List sessions
List the caller's sessions ordered by (updated_at DESC, id DESC) with cursor
pagination. When q is set, all title matches are returned in one shot
(pagination is bypassed).
GET /api/sessions · Authorization: Bearer <key> or X-API-Key · Optional
X-Org-ID.
| Query param | Type | Required | Description |
|---|---|---|---|
q | string | null | no | Filters session titles (ILIKE). When set, pagination is bypassed. |
include_archived | boolean | no | Include archived sessions. Default false. |
limit | integer | no | Page size, 1–200. Default 50. |
cursor | string | null | no | Opaque cursor from a prior next_cursor. Omit for the first page. |
curl "https://api.cognitivx.io/api/sessions?limit=20" \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"sessions": [
{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"provider": "openrouter",
"model": "openai/gpt-oss-120b",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-15T09:31:44Z",
"message_count": 8,
"last_message_preview": "You decided to move sessions to JWT...",
"category_id": null,
"category_name": null,
"is_pinned": false,
"is_archived": false,
"initiated_by": null,
"unread": false
}
],
"total": 1,
"next_cursor": "2026-06-15T09:31:44+00:00|5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"has_more": true
}total is the count of the current page, not the full collection. To page,
pass the returned next_cursor back as cursor. next_cursor is null when
there are no more pages, and is always null when q is set (search is
single-shot).
Errors: 401 invalid key. 400 "Invalid cursor" when the cursor is
malformed. 422 when limit is outside 1–200.
Create session
Create an empty chat session. Use the returned id as session_id for
/api/chat/stream.
POST /api/sessions · Authorization: Bearer <key> or X-API-Key · Optional
X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | no | Session title. Default "New Chat". |
curl https://api.cognitivx.io/api/sessions \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Auth migration plan"}'{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"provider": null,
"model": null,
"created_at": "2026-06-16T10:00:00Z",
"updated_at": "2026-06-16T10:00:00Z",
"message_count": 0,
"last_message_preview": null
}The title is optional and may be overwritten: the chat pipeline auto-titles a session from its first exchange.
Errors: 401 invalid key. 422 malformed body.
Get session
Fetch a single session with its current message_count and
last_message_preview.
GET /api/sessions/{session_id} · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
| Path param | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | yes | The session to fetch. |
curl https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"provider": "openrouter",
"model": "openai/gpt-oss-120b",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-15T09:31:44Z",
"message_count": 8,
"last_message_preview": "You decided to move sessions to JWT..."
}Errors: 401 invalid key. 404 "Session not found" (also returned for
sessions owned by another user).
Rename session
Update a session's title.
PATCH /api/sessions/{session_id} · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | New title. |
curl -X PATCH https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title": "Auth migration (final)"}'{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration (final)",
"provider": "openrouter",
"model": "openai/gpt-oss-120b",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-16T10:05:00Z",
"message_count": 8,
"last_message_preview": "You decided to move sessions to JWT..."
}Errors: 401 invalid key. 404 "Session not found". 422 missing
title.
Delete session
Delete a session and all of its messages.
DELETE /api/sessions/{session_id} · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID.
| Path param | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | yes | The session to delete. |
curl -X DELETE https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{ "message": "Session deleted" }Errors: 401 invalid key. 404 "Session not found".
Get session messages
Return the full ordered message history for a session, including each message's recalled memories, web sources, UI blocks, and tool invocations.
GET /api/sessions/{session_id}/messages · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID.
| Path param | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | yes | The session whose messages to fetch. |
curl https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/messages \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"messages": [
{
"id": "9d0b1a2c-3e4f-4a5b-8c6d-7e8f9a0b1c2d",
"session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"role": "user",
"content": "What did we decide about the auth migration?",
"provider": null,
"model": null,
"created_at": "2026-06-15T09:31:40Z",
"recalled_memories": null,
"web_sources": null,
"ui_blocks": null,
"tool_invocations": null
},
{
"id": "7c1e9a02-3b4d-4f6a-8c2e-9d0b1a2c3e4f",
"session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"role": "assistant",
"content": "You decided to move sessions to JWT...",
"provider": "openrouter",
"model": "openai/gpt-oss-120b",
"created_at": "2026-06-15T09:31:44Z",
"recalled_memories": { "count": 12 },
"web_sources": [],
"ui_blocks": [],
"tool_invocations": []
}
]
}recalled_memories is an object (or null); web_sources, ui_blocks, and
tool_invocations are arrays (or null).
Errors: 401 invalid key. An unknown or unowned session returns
{ "messages": [] } rather than 404.
Delete message
Delete a single message by id.
DELETE /api/sessions/{session_id}/messages/{message_id} ·
Authorization: Bearer <key> or X-API-Key · Optional X-Org-ID.
| Path param | Type | Required | Description |
|---|---|---|---|
session_id | string (UUID) | yes | Kept for REST consistency; not used for lookup. |
message_id | string (UUID) | yes | The message to delete. |
curl -X DELETE https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/messages/7c1e9a02-3b4d-4f6a-8c2e-9d0b1a2c3e4f \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{ "message": "Message deleted" }Errors: 401 invalid key. 404 "Message not found".
Search messages
Search message content across all of the caller's sessions.
GET /api/sessions/search · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
| Query param | Type | Required | Description |
|---|---|---|---|
q | string | yes | Search query. Queries shorter than 2 chars return an empty result. |
curl "https://api.cognitivx.io/api/sessions/search?q=auth%20migration" \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"results": [
{
"session_id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"message_id": "7c1e9a02-3b4d-4f6a-8c2e-9d0b1a2c3e4f",
"content": "...auth migration...",
"role": "assistant"
}
]
}The result shape is a loose dict, not a typed model.
Errors: 401 invalid key. Returns { "results": [] } when q is empty or
shorter than 2 characters (no error).
Export sessions
Download all of the caller's sessions and messages as a single JSON or Markdown
file. Both forms set Content-Disposition: attachment.
GET /api/sessions/export · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
| Query param | Type | Required | Description |
|---|---|---|---|
format | string | no | "json" (default) or "markdown". Any value other than "markdown" yields JSON. |
curl "https://api.cognitivx.io/api/sessions/export?format=markdown" \
-H "Authorization: Bearer $COGNITIVX_API_KEY" -o icog-export.mdJSON form:
{
"exported_at": "2026-06-16T10:00:00Z",
"user_email": "[email protected]",
"sessions": [
{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-15T09:31:44Z",
"messages": [
{ "role": "user", "content": "...", "created_at": "..." }
]
}
]
}The Markdown form returns text/markdown.
Errors: 401 invalid key.
Move session to category
Move a session into a category, or to Unsorted when category_id is null.
PUT /api/sessions/{session_id}/move · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
category_id | string | null | yes | Target category id, or null for Unsorted. Send null explicitly to unsort. |
curl -X PUT https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/move \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"category_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"}'{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-16T10:10:00Z",
"message_count": 8,
"category_id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"category_name": null,
"is_pinned": false,
"is_archived": false
}category_name is not populated by the move response.
Errors: 401 invalid key. 404 "Session or category not found". 422
when the category_id key is missing (send null explicitly to unsort).
Toggle session pin
Toggle the pinned state. Pinning also unarchives; unpinning leaves the archive state unchanged.
PUT /api/sessions/{session_id}/pin · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID. No body.
curl -X PUT https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/pin \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-16T10:11:00Z",
"message_count": 8,
"is_pinned": true,
"is_archived": false,
"category_id": null,
"category_name": null
}Errors: 401 invalid key. 404 "Session not found".
Toggle session archive
Toggle the archived state. Archiving also unpins; unarchiving leaves the pin state unchanged.
PUT /api/sessions/{session_id}/archive · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID. No body.
curl -X PUT https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/archive \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"id": "5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d",
"title": "Auth migration plan",
"created_at": "2026-06-10T14:02:11Z",
"updated_at": "2026-06-16T10:12:00Z",
"message_count": 8,
"is_pinned": false,
"is_archived": true,
"category_id": null,
"category_name": null
}Errors: 401 invalid key. 404 "Session not found".
Promote session to Circle
Convert a private chat session into a (private) Circle, copying all messages into it with the caller as owner. The session title is truncated to 100 chars for the Circle's name and subject.
POST /api/sessions/{session_id}/promote-to-circle ·
Authorization: Bearer <key> or X-API-Key · Optional X-Org-ID. No body.
curl -X POST https://api.cognitivx.io/api/sessions/5f3c9b2a-1d4e-4a7b-9c8d-2e1f0a3b4c5d/promote-to-circle \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"id": "c0ffee00-1111-4222-8333-444455556666",
"name": "Auth migration plan",
"subject": "Auth migration plan",
"description": null,
"visibility": "private",
"avatar_url": null,
"member_count": 1,
"role": "owner",
"budget_tokens_monthly": null,
"budget_used_tokens": 0,
"created_at": "2026-06-16T10:12:00Z",
"updated_at": "2026-06-16T10:12:00Z"
}Errors: 401 invalid key. 404 "Session not found".
Categories
Categories are folders for organizing sessions. The category routes are declared
before the /{session_id} and /{category_id} routes so that
/api/sessions/categories and /api/sessions/categories/reorder are never
shadowed by an id path.
Create category
POST /api/sessions/categories · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Category name. |
color | string | no | Hex color. Default "#8b5cf6". |
icon | string | no | Icon name. Default "folder". |
curl https://api.cognitivx.io/api/sessions/categories \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Engineering", "color": "#7c3aed", "icon": "code"}'{
"id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "Engineering",
"position": 0,
"color": "#7c3aed",
"icon": "code",
"created_at": "2026-06-16T10:15:00Z",
"updated_at": "2026-06-16T10:15:00Z"
}Errors: 401 invalid key. 422 missing name.
List categories
GET /api/sessions/categories · Authorization: Bearer <key> or X-API-Key ·
Optional X-Org-ID. No params.
curl https://api.cognitivx.io/api/sessions/categories \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{
"categories": [
{
"id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "Engineering",
"position": 0,
"color": "#7c3aed",
"icon": "code",
"created_at": "2026-06-16T10:15:00Z",
"updated_at": "2026-06-16T10:15:00Z"
}
]
}Categories are returned in position order.
Errors: 401 invalid key.
Update category
Rename a category or change its color/icon. All fields are optional; omitted or empty fields keep their current value.
PATCH /api/sessions/categories/{category_id} · Authorization: Bearer <key>
or X-API-Key · Optional X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | null | no | New name. Current name kept if omitted/empty. |
color | string | null | no | New hex color. |
icon | string | null | no | New icon name. |
curl -X PATCH https://api.cognitivx.io/api/sessions/categories/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Eng & Infra"}'{
"id": "a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "Eng & Infra",
"position": 0,
"color": "#7c3aed",
"icon": "code",
"created_at": "2026-06-16T10:15:00Z",
"updated_at": "2026-06-16T10:20:00Z"
}Errors: 401 invalid key. 404 "Category not found".
Delete category
Delete a category. Its sessions move to Unsorted.
DELETE /api/sessions/categories/{category_id} · Authorization: Bearer <key>
or X-API-Key · Optional X-Org-ID.
curl -X DELETE https://api.cognitivx.io/api/sessions/categories/a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d \
-H "Authorization: Bearer $COGNITIVX_API_KEY"{ "message": "Category deleted" }Errors: 401 invalid key. 404 "Category not found".
Reorder categories
Set the category display order from an ordered list of ids.
PUT /api/sessions/categories/reorder · Authorization: Bearer <key> or
X-API-Key · Optional X-Org-ID.
| Field | Type | Required | Description |
|---|---|---|---|
category_ids | string[] | yes | Category ids in the desired order. |
curl -X PUT https://api.cognitivx.io/api/sessions/categories/reorder \
-H "Authorization: Bearer $COGNITIVX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"category_ids": ["a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "b2c3d4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e"]}'{ "message": "Categories reordered" }Errors: 401 invalid key. 422 missing category_ids.
Related
- Authentication & keys — how to mint the key used on every request here.
- Build a chat app with iCog — an end-to-end streaming example.