Developer Documentation

API Reference

Complete reference for the Akili REST API — authentication, endpoints, rate limits, and error codes.

Base URL

All API endpoints are served from the NestJS backend, proxied through the Next.js frontend at /backend/*. When calling from outside the frontend (e.g. from your own application), call the backend directly:

# Production (internal network only)
https://your-backend.internal/api/

# Via the frontend proxy (public, authenticated)
https://your-domain.com/backend/

Authentication

Every request must include a valid credential. Two methods are supported:

MethodHeaderUse case
Session cookieCookie: better-auth.session_token=...Browser clients (set automatically after sign-in)
API keyX-API-Key: ak_...Server-to-server, CLI tools, CI/CD
API key (Bearer)Authorization: Bearer ak_...Alternative to X-API-Key header
Note: Create API keys in Settings → Auth Keys. Keys are prefixed with ak_ and shown only once at creation.

Core endpoints

MethodPathDescription
GET/api/chatsList user's conversations
POST/api/chatSend a chat message (SSE stream)
GET/api/chats/:id/messagesGet messages for a chat
GET/api/agentsList available agents
POST/api/agents/:id/chatChat with a specific agent (SSE)
GET/api/knowledge-basesList knowledge bases
POST/api/knowledge-bases/:id/searchSemantic search a knowledge base
GET/api/modelsList available AI models
GET/api/marketplace/listingsBrowse marketplace
GET/api/healthHealth check (no auth required)

Streaming chat (SSE)

Chat responses stream as Server-Sent Events. Connect with EventSource or fetch with a ReadableStream:

const response = await fetch("/backend/chat/stream", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",      // sends session cookie
  body: JSON.stringify({
    chatId: "optional-existing-chat-id",
    model: "gpt-4.1-mini",
    messages: [{ role: "user", content: "Hello!" }],
    enableSearch: false,
    knowledgeBaseIds: [],
  }),
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const text = decoder.decode(value);
  for (const line of text.split("\n")) {
    if (!line.startsWith("data: ")) continue;
    const data = line.slice(6);
    if (data === "[DONE]") break;
    const { textDelta } = JSON.parse(data);
    process.stdout.write(textDelta);
  }
}

Rate limits

TierRequests / minuteChat messages / day
Free2050
Pro100500
EnterpriseUnlimitedUnlimited
API key200Same as user tier
Note: Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Error codes

HTTPCodeMeaning
400VALIDATION_ERRORRequest body failed validation
401UNAUTHORIZEDMissing or invalid credentials
403FORBIDDENValid credentials but insufficient permissions
404NOT_FOUNDResource does not exist
429RATE_LIMITEDToo many requests — back off and retry
500INTERNAL_ERRORServer error — contact your administrator
503BACKEND_UNAVAILABLENestJS backend is not reachable