Skip to content

Faster Chat — API Reference

Last Updated: 2026-04-23 Base URL: http://localhost:3001/api (dev) / your deployment URL (prod) Runtime: Bun + Hono Auth: Cookie-based sessions (httpOnly, sameSite=lax)



All protected endpoints use cookie-based session authentication. The session cookie is set automatically after login or registration and is sent with every request (credentials: true).

After a successful POST /api/auth/login or POST /api/auth/register, the server sets an httpOnly cookie named session. The frontend sends this cookie automatically via fetch/XMLHttpRequest with credentials: "include".

GET /api/auth/session

Returns the currently authenticated user or 401 if no valid session exists.

RoleDescription
adminFull access — users, providers, models, settings
memberFull chat access + import conversations
readonlyView-only access (chat endpoints work, admin blocked)

The first registered user automatically becomes admin. Subsequent registrations are locked until an admin creates accounts via POST /api/admin/users.


All error responses follow a consistent JSON format:

{
"error": "Human-readable error message"
}

Validation errors include details:

{
"error": "Invalid input",
"details": [
{ "code": "too_short", "message": "String must contain at least 3 character(s)", "path": ["username"] }
]
}
CodeMeaning
200OK
201Created
204No Content
400Bad Request (validation failure)
401Unauthorized (missing/expired session)
403Forbidden (insufficient role)
404Not Found
409Conflict
413Request body too large (>50 MB)
429Too Many Requests (rate limited)
500Internal Server Error

  • Window: 15 minutes
  • Max attempts: 5 per IP and per username
  • Cleanup runs every 5 minutes
EndpointLimit
Chat completion20 requests / minute per user
Image generation5 requests / minute per user
File upload10 requests / minute per user
Ollama model pull3 requests / 5 minutes per user

All /api/* requests are rejected with 413 if Content-Length exceeds 50 MB.



Manage user authentication and sessions.

Register a new user. Only available when no users exist (first-user registration).

Endpoint:

POST /api/auth/register

Authentication: None (public)

Request Body:

FieldTypeRequiredConstraints
usernamestringYes3–50 characters
passwordstringYes8–100 characters

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/auth/register \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "supersecret123"}' \
-c cookies.txt

Success Response (201):

{
"user": {
"id": 1,
"username": "admin",
"role": "admin"
},
"session": {
"expiresAt": 1782950400000
}
}

Possible Errors:

  • 403 — Registration disabled (users already exist)
  • 400 — Invalid input or username taken
  • 429 — Rate limit exceeded

Authenticate with username and password.

Endpoint:

POST /api/auth/login

Authentication: None (public)

Request Body:

FieldTypeRequired
usernamestringYes
passwordstringYes

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "supersecret123"}' \
-c cookies.txt

Success Response (200):

{
"user": {
"id": 1,
"username": "admin",
"role": "admin"
},
"session": {
"expiresAt": 1782950400000
}
}

Possible Errors:

  • 401 — Invalid credentials (generic message for security)
  • 429 — Rate limit exceeded

Destroy the current session and clear the session cookie.

Endpoint:

POST /api/auth/logout

Authentication: Session cookie (optional — works even without one)

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/auth/logout \
-b cookies.txt

Success Response (200):

{
"success": true
}

Check the current session and return user info.

Endpoint:

GET /api/auth/session

Authentication: Session cookie

Example Request:

Terminal window
curl http://localhost:3001/api/auth/session \
-b cookies.txt

Success Response (200):

{
"user": {
"id": 1,
"username": "admin",
"role": "admin"
},
"session": {
"expiresAt": 1782950400000
}
}

Not Logged In (401):

{
"user": null
}

Change the authenticated user’s password. Invalidates all existing sessions.

Endpoint:

PUT /api/auth/change-password

Authentication: Session cookie

Request Body:

FieldTypeRequiredConstraints
currentPasswordstringYesMust match current password
newPasswordstringYes8–100 characters

Example Request:

Terminal window
curl -X PUT http://localhost:3001/api/auth/change-password \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"currentPassword": "oldpass123", "newPassword": "newpass456"}'

Success Response (200):

{
"success": true,
"session": {
"expiresAt": 1782950400000
}
}

Possible Errors:

  • 401 — Current password is incorrect
  • 400 — Invalid input

CRUD operations for conversations. All chat endpoints require authentication and scope data to the authenticated user.

Retrieve paginated chats for the current user (excludes archived and deleted).

Endpoint:

GET /api/chats

Authentication: Session cookie

Query Parameters:

ParameterTypeDefaultMaxDescription
limitinteger50100Number of chats to return
offsetinteger0Pagination offset

Example Request:

Terminal window
curl "http://localhost:3001/api/chats?limit=20&offset=0" \
-b cookies.txt

Success Response (200):

{
"chats": [
{
"id": "abc-123",
"title": "Help with React hooks",
"folderId": null,
"pinnedAt": null,
"archivedAt": null,
"createdAt": 1710000000000,
"updatedAt": 1710000060000
}
],
"limit": 20,
"offset": 0
}

Create a new empty chat.

Endpoint:

POST /api/chats

Authentication: Session cookie

Request Body:

FieldTypeRequiredDescription
idstringNoCustom chat ID (UUID, auto-generated if omitted)
titlestringNoInitial title (auto-generated from first message)
folder_idstringNoFolder UUID to place chat in

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/chats \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"title": "My new chat", "folder_id": "folder-uuid"}'

Success Response (201):

{
"id": "abc-123",
"title": "My new chat",
"folderId": "folder-uuid",
"createdAt": 1710000000000,
"updatedAt": 1710000000000
}

Retrieve a single chat by ID.

Endpoint:

GET /api/chats/:chatId

Authentication: Session cookie

Example Request:

Terminal window
curl http://localhost:3001/api/chats/abc-123 \
-b cookies.txt

Success Response (200):

{
"id": "abc-123",
"title": "Help with React hooks",
"memoryDisabled": false,
"createdAt": 1710000000000,
"updatedAt": 1710000060000
}

Update a chat’s title.

Endpoint:

PATCH /api/chats/:chatId

Authentication: Session cookie

Request Body:

FieldTypeRequiredConstraints
titlestringNoMax 200 characters

Example Request:

Terminal window
curl -X PATCH http://localhost:3001/api/chats/abc-123 \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"title": "Updated title"}'

Success Response (200):

{
"id": "abc-123",
"title": "Updated title",
"createdAt": 1710000000000,
"updatedAt": 1710000120000
}

Soft-delete a chat (sets deleted_at, not permanently removed).

Endpoint:

DELETE /api/chats/:chatId

Authentication: Session cookie

Example Request:

Terminal window
curl -X DELETE http://localhost:3001/api/chats/abc-123 \
-b cookies.txt

Success Response (200):

{
"message": "Chat deleted successfully"
}

Pin a chat to the top of the list.

Endpoint:

POST /api/chats/:chatId/pin

Authentication: Session cookie

Success Response (200):

{
"message": "Chat pinned successfully"
}

Remove pin from a chat.

Endpoint:

DELETE /api/chats/:chatId/pin

Authentication: Session cookie

Success Response (200):

{
"message": "Chat unpinned successfully"
}

Move a chat to the archive.

Endpoint:

POST /api/chats/:chatId/archive

Authentication: Session cookie

Success Response (200):

{
"message": "Chat archived successfully"
}

Restore a chat from the archive.

Endpoint:

DELETE /api/chats/:chatId/archive

Authentication: Session cookie

Success Response (200):

{
"message": "Chat unarchived successfully"
}

Enable or disable memory for a specific chat.

Endpoint:

PUT /api/chats/:chatId/memory

Authentication: Session cookie

Request Body:

FieldTypeRequired
disabledbooleanYes

Example Request:

Terminal window
curl -X PUT http://localhost:3001/api/chats/abc-123/memory \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"disabled": true}'

Success Response (200):

{
"disabled": true
}

Manage messages within a chat. All endpoints require authentication and scope to the chat owner.

Retrieve paginated messages for a chat.

Endpoint:

GET /api/chats/:chatId/messages

Authentication: Session cookie

Query Parameters:

ParameterTypeDefaultMaxDescription
limitinteger200500Number of messages to return
offsetinteger0Pagination offset

Example Request:

Terminal window
curl "http://localhost:3001/api/chats/abc-123/messages?limit=50&offset=0" \
-b cookies.txt

Success Response (200):

{
"messages": [
{
"id": "msg-001",
"role": "user",
"content": "What is React?",
"model": null,
"fileIds": null,
"metadata": null,
"createdAt": 1710000000000
},
{
"id": "msg-002",
"role": "assistant",
"content": "React is a JavaScript library...",
"model": "gpt-4o",
"fileIds": null,
"metadata": null,
"createdAt": 1710000001000
}
],
"limit": 50,
"offset": 0
}

Add a message to a chat. First user message auto-generates the chat title (with AI upgrade if model supports it).

Endpoint:

POST /api/chats/:chatId/messages

Authentication: Session cookie

Request Body:

FieldTypeRequiredConstraints
idstringNoCustom message ID (auto-generated if omitted)
rolestringYes"user", "assistant", or "system"
contentstringYesMax 100,000 characters
modelstringNoModel ID (for assistant messages)
fileIdsstring[]NoArray of file attachment IDs
metadataobjectNoArbitrary JSON metadata

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/chats/abc-123/messages \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"role": "user", "content": "Explain closures in JavaScript"}'

Success Response (201):

{
"id": "msg-003",
"chatId": "abc-123",
"role": "user",
"content": "Explain closures in JavaScript",
"model": null,
"fileIds": null,
"metadata": null,
"createdAt": 1710000002000
}

Remove a single message from a chat.

Endpoint:

DELETE /api/chats/:chatId/messages/:messageId

Authentication: Session cookie

Success Response (200):

{
"message": "Message deleted successfully"
}

Generate an AI completion for a chat. Returns a Server-Sent Events (SSE) stream using the Vercel AI SDK’s UIMessageStreamResponse format.

Endpoint:

POST /api/chats/:chatId/completion

Authentication: Session cookie

Request Body:

FieldTypeRequiredDescription
modelstringYesModel ID (e.g., "gpt-4o", "claude-sonnet-4-20250514")
systemPromptIdstringNoSystem prompt template ID (default: "default")
messagesarrayYesArray of { id, role, content, fileIds? } objects
fileIdsstring[]NoLegacy: file attachments for last user message
webSearchbooleanNoEnable web search tool (requires Brave API key + tool-supporting model)
memoryEnabledbooleanNoEnable memory extraction (default: true)

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/chats/abc-123/completion \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"systemPromptId": "default",
"messages": [
{ "id": "msg-001", "role": "user", "content": "What is React?" },
{ "id": "msg-002", "role": "assistant", "content": "React is a JavaScript library..." }
],
"webSearch": false,
"memoryEnabled": true
}'

Response: SSE stream (text/event-stream)

The response follows the Vercel AI SDK UIMessageStreamResponse format. Frontend consumption uses the AI SDK’s useChat hook or createUIMessageStreamReadable.

Stream events include:

  • 0 — Text delta (partial content chunks)
  • 6 — Part start (tool calls, file annotations)
  • T — Text done (final text for a part)
  • e — Error
  • p — Partial text update
  • d — Done (stream complete, includes finishReason and usage)

Possible Errors:

  • 400 — Invalid request body
  • 403 — Invalid file attachments
  • 404 — Chat not found
  • 429 — Rate limit exceeded (20/min)
  • 500 — Completion failed

Upload, manage, and download file attachments.

Upload a file attachment.

Endpoint:

POST /api/files

Authentication: Session cookie

Request: multipart/form-data with a file field.

Supported types: Images (JPEG, PNG, GIF, WebP, SVG, BMP), Documents (PDF, TXT, MD, CSV, JSON, XML, HTML), Code files

Max size: 50 MB (global body limit)

Example Request:

Terminal window
curl -X POST http://localhost:3001/api/files \
-b cookies.txt \
-F "file=@/path/to/image.png"

Success Response (201):

{
"id": "f_abc123",
"filename": "image.png",
"size": 245760,
"sizeFormatted": "240 KB",
"mimeType": "image/png",
"hash": "sha256:a1b2c3...",
"createdAt": 1710000000000
}

Retrieve all files for the current user.

Endpoint:

GET /api/files

Authentication: Session cookie

Success Response (200):

{
"files": [
{
"id": "f_abc123",
"filename": "image.png",
"size": 245760,
"sizeFormatted": "240 KB",
"mimeType": "image/png",
"createdAt": 1710000000000
}
],
"total": 1
}

Retrieve metadata for a single file.

Endpoint:

GET /api/files/:id

Authentication: Session cookie

Success Response (200):

{
"id": "f_abc123",
"filename": "image.png",
"size": 245760,
"sizeFormatted": "240 KB",
"mimeType": "image/png",
"hash": "sha256:a1b2c3...",
"createdAt": 1710000000000,
"meta": {
"originalName": "image.png",
"uploadedAt": 1710000000000
}
}

Download the raw file content.

Endpoint:

GET /api/files/:id/content

Authentication: Session cookie

Response: Raw file bytes with Content-Type and Content-Disposition headers.

Example Request:

Terminal window
curl http://localhost:3001/api/files/f_abc123/content \
-b cookies.txt \
-o downloaded-image.png

Note: SVG files are served as attachment (not inline) to prevent stored XSS.


Delete a file from disk and database.

Endpoint:

DELETE /api/files/:id

Authentication: Session cookie

Success Response (200):

{
"message": "File deleted successfully"
}

Organize chats into folders.

Endpoint:

GET /api/folders

Authentication: Session cookie

Success Response (200):

{
"folders": [
{
"id": "folder-uuid",
"user_id": 1,
"name": "Work",
"color": "#FF5733",
"position": 0,
"is_collapsed": 0,
"created_at": 1710000000000,
"updated_at": 1710000000000
}
]
}

Endpoint:

GET /api/folders/:id

Authentication: Session cookie


Endpoint:

GET /api/folders/:id/chats

Authentication: Session cookie

Success Response (200):

{
"chats": [
{
"id": "chat-uuid",
"title": "Chat in this folder",
"folder_id": "folder-uuid",
"created_at": 1710000000000,
"updated_at": 1710000000000
}
]
}

Endpoint:

POST /api/folders

Authentication: Session cookie

Request Body:

FieldTypeRequiredConstraints