Skip to content

Overview

The Ask API consists of three parts:

  1. Ticket endpoint -- Issues a short-lived HMAC ticket for direct worker connection
  2. Worker SSE endpoint -- Receives the ticket and streams the AI answer via Server-Sent Events
  3. Chat Sessions CRUD -- Manage chat sessions and messages

POST /api/v2/ask

Issues a signed HMAC ticket that the client uses to connect directly to the VPS worker for SSE streaming. This endpoint handles authentication and quota checks only -- the actual AI processing happens on the worker.

Authentication

Session cookie or Bearer API key via deriveAuthV2().

Request body

FieldTypeRequiredDescription
projectIdstringYesThe project to query
questionstringYesThe question to ask (min 3 characters)
chatSessionIdstringNoExisting chat session ID to continue a conversation

Example request

bash
curl -X POST https://contox.dev/api/v2/ask \
  -H "Content-Type: application/json" \
  -H "Cookie: a_session_..." \
  -d '{
    "projectId": "proj_abc123",
    "question": "How does the authentication middleware work?",
    "chatSessionId": "sess_xyz789"
  }'

Success response (200)

json
{
  "ticket": "eyJwaWQiOiJwcm9qX2FiYzEyMyIs...",
  "workerUrl": "https://worker.example.com"
}
FieldTypeDescription
ticketstringHMAC-signed ticket in base64url(payload).signature format. Valid for 60 seconds.
workerUrlstringThe VPS worker URL to connect to for SSE streaming

Ticket payload

The ticket contains the following claims, signed with WORKER_API_SECRET:

json
{
  "pid": "proj_abc123",
  "tid": "team_def456",
  "uid": "user_ghi789",
  "sid": "sess_xyz789",
  "exp": 1705312260000
}

Error responses

StatusErrorCause
400projectId is requiredMissing projectId in request body
400question is required (min 3 chars)Missing or too-short question
401UnauthorizedInvalid or missing authentication
403AI token limit reachedTeam has exceeded AI token quota
503Worker not configuredWORKER_URL or WORKER_API_SECRET not set

POST /ask

The SSE streaming endpoint on the VPS worker. The client connects directly to this endpoint with the ticket obtained from /api/v2/ask.

Request body

FieldTypeRequiredDescription
ticketstringYesThe HMAC ticket from /api/v2/ask
questionstringYesThe question to ask (min 3 characters)

Example request

bash
curl -X POST https://worker.example.com/ask \
  -H "Content-Type: application/json" \
  -d '{
    "ticket": "eyJwaWQiOiJwcm9qX2FiYzEyMyIs...",
    "question": "How does the authentication middleware work?"
  }'

Response format

The response is an SSE stream (Content-Type: text/event-stream). Each event is a data: line containing a JSON object.

SSE event types

token

Streamed incrementally as the LLM generates the answer. Each event contains a small chunk of text.

data: {"type":"token","content":"The authentication"}

data: {"type":"token","content":" middleware uses"}

data: {"type":"token","content":" JWT tokens..."}
FieldTypeDescription
type"token"Event type identifier
contentstringA chunk of the answer text

done

Sent once when the answer is complete. Contains the full answer, sources, token usage, and metadata.

data: {"type":"done","answer":"The authentication middleware uses JWT tokens...","sources":[...],"avgSimilarity":0.78,"usage":{"promptTokens":1200,"completionTokens":350,"totalTokens":1550},"model":"gemini-2.0-flash"}
FieldTypeDescription
type"done"Event type identifier
answerstringThe complete answer text (markdown)
sourcesarrayArray of search result objects (see below)
avgSimilaritynumberAverage cosine similarity across all sources
usageobjectToken usage: promptTokens, completionTokens, totalTokens
modelstringThe model used (e.g., "gemini-2.0-flash")
embedUsageobjectEmbedding token usage: { totalTokens }
errorstring | undefinedIf the LLM failed, this contains the error message instead of answer

done (error variant)

If the LLM encounters an error during streaming, the done event includes an error field instead of answer:

data: {"type":"done","error":"Model rate limited, please try again"}

Keepalive

The server sends SSE comments every 5 seconds to keep the connection alive:

: keepalive

Source object

Each entry in the sources array has this shape:

FieldTypeDescription
itemIdstringThe memory item's document ID
typestringItem type (e.g., architecture_pattern, implementation, convention, bug)
titlestringMemory item title
factsstringMemory item facts text
schemaKeystringThe item's schema key in the brain hierarchy
similaritynumberCosine similarity score (0.50--1.0)
confidencenumberItem confidence score (0.0--1.0)
filesstring[]File paths associated with the item
usedbooleanWhether the AI explicitly cited this source in the answer

Error responses

StatusErrorCause
400Invalid JSONMalformed request body
400question is required (min 3 chars)Missing or too-short question
401Invalid or expired ticketTicket signature invalid, expired, or missing

Chat Sessions

Chat sessions group Ask conversations. All session endpoints use session cookie or Bearer API key authentication via deriveAuthV2().

GET /api/v2/chat-sessions

List chat sessions for a project.

Query parameters

ParameterTypeRequiredDefaultDescription
projectIdstringYes--The project to list sessions for
limitnumberNo50Max sessions to return (1--200)
offsetnumberNo0Pagination offset
favorites"true"No--Filter to only favorited sessions
searchstringNo--Full-text search on session title (min 2 chars)

Example request

bash
curl "https://contox.dev/api/v2/chat-sessions?projectId=proj_abc123&limit=20&favorites=true" \
  -H "Cookie: a_session_..."

Success response (200)

json
{
  "sessions": [
    {
      "id": "sess_abc123",
      "projectId": "proj_abc123",
      "userId": "user_def456",
      "title": "How does authentication work?",
      "messageCount": 6,
      "aiTokensUsed": 4500,
      "storageTokens": 1200,
      "model": "gemini-2.0-flash",
      "favoritedBy": ["user_def456"],
      "status": "active",
      "lastMessageAt": "2026-02-16T10:30:00.000Z",
      "createdAt": "2026-02-16T10:00:00.000Z"
    }
  ],
  "total": 1
}

POST /api/v2/chat-sessions

Create a new chat session.

Request body

FieldTypeRequiredDefaultDescription
projectIdstringYes--The project to create the session for
titlestringNo"New conversation"Session title

Example request

bash
curl -X POST https://contox.dev/api/v2/chat-sessions \
  -H "Content-Type: application/json" \
  -H "Cookie: a_session_..." \
  -d '{
    "projectId": "proj_abc123",
    "title": "Authentication deep dive"
  }'

Success response (200)

json
{
  "ok": true,
  "sessionId": "sess_abc123",
  "session": {
    "id": "sess_abc123",
    "projectId": "proj_abc123",
    "userId": "user_def456",
    "title": "Authentication deep dive",
    "messageCount": 0,
    "aiTokensUsed": 0,
    "storageTokens": 0,
    "model": null,
    "favoritedBy": [],
    "status": "active",
    "lastMessageAt": "2026-02-16T10:00:00.000Z",
    "createdAt": "2026-02-16T10:00:00.000Z"
  }
}

GET /api/v2/chat-sessions/:id

Get a single chat session's details including token statistics.

Path parameters

ParameterTypeDescription
idstringThe chat session ID

Success response (200)

Returns the same session object shape as the list endpoint.

Error responses

StatusErrorCause
401UnauthorizedInvalid or missing authentication
404Session not foundNo session with this ID exists

PATCH /api/v2/chat-sessions/:id

Update a chat session's title or status.

Path parameters

ParameterTypeDescription
idstringThe chat session ID

Request body

FieldTypeRequiredDescription
titlestringNoNew session title (max 256 characters)
status"archived"NoSet to "archived" to archive the session

Example request

bash
curl -X PATCH https://contox.dev/api/v2/chat-sessions/sess_abc123 \
  -H "Content-Type: application/json" \
  -H "Cookie: a_session_..." \
  -d '{"title": "Auth middleware deep dive"}'

Success response (200)

json
{
  "ok": true,
  "sessionId": "sess_abc123"
}

Error responses

StatusErrorCause
400No valid fields to updateRequest body contained no valid fields
401UnauthorizedInvalid or missing authentication
404Session not foundNo session with this ID exists

DELETE /api/v2/chat-sessions/:id

Delete a chat session and all its messages. Storage tokens used by the session are decremented from the team's rollup.

Path parameters

ParameterTypeDescription
idstringThe chat session ID

Example request

bash
curl -X DELETE https://contox.dev/api/v2/chat-sessions/sess_abc123 \
  -H "Cookie: a_session_..."

Success response (200)

json
{
  "ok": true,
  "sessionId": "sess_abc123"
}

Error responses

StatusErrorCause
401UnauthorizedInvalid or missing authentication
404Session not foundNo session with this ID exists

POST /api/v2/chat-sessions/:id/favorite

Toggle the favorite status for the current user on a chat session.

Path parameters

ParameterTypeDescription
idstringThe chat session ID

Example request

bash
curl -X POST https://contox.dev/api/v2/chat-sessions/sess_abc123/favorite \
  -H "Cookie: a_session_..."

Success response (200)

json
{
  "ok": true,
  "favorited": true
}
FieldTypeDescription
favoritedbooleantrue if the session is now favorited, false if unfavorited

GET /api/v2/chat-sessions/:id/messages

List messages for a chat session, ordered chronologically (oldest first).

Path parameters

ParameterTypeDescription
idstringThe chat session ID

Query parameters

ParameterTypeRequiredDefaultDescription
limitnumberNo200Max messages to return (1--500)
cursorstringNo--Cursor for pagination (message ID to start after)

Example request

bash
curl "https://contox.dev/api/v2/chat-sessions/sess_abc123/messages?limit=50" \
  -H "Cookie: a_session_..."

Success response (200)

json
{
  "messages": [
    {
      "id": "msg_001",
      "role": "user",
      "content": "How does authentication work?",
      "sources": [],
      "promptTokens": 0,
      "completionTokens": 0,
      "totalTokens": 0,
      "model": null,
      "createdAt": "2026-02-16T10:00:00.000Z"
    },
    {
      "id": "msg_002",
      "role": "assistant",
      "content": "The authentication system uses JWT tokens with...",
      "sources": [
        {
          "itemId": "item_abc",
          "type": "architecture_pattern",
          "title": "JWT Auth Middleware",
          "facts": "The auth middleware validates...",
          "schemaKey": "root/architecture/auth",
          "similarity": 0.87,
          "confidence": 0.95,
          "files": ["src/middleware/auth.ts"],
          "used": true
        }
      ],
      "promptTokens": 1200,
      "completionTokens": 350,
      "totalTokens": 1550,
      "model": "gemini-2.0-flash",
      "createdAt": "2026-02-16T10:00:05.000Z"
    }
  ],
  "total": 2
}

Message object

FieldTypeDescription
idstringMessage document ID
role"user" | "assistant"Who sent the message
contentstringThe message text (markdown for assistant messages)
sourcesarrayArray of source objects (empty for user messages)
promptTokensnumberPrompt tokens used (0 for user messages)
completionTokensnumberCompletion tokens used (0 for user messages)
totalTokensnumberTotal tokens used (0 for user messages)
modelstring | nullModel used (null for user messages)
createdAtstringISO 8601 timestamp

Next steps