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)
Table of Contents
Section titled “Table of Contents”Authentication
Section titled “Authentication”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).
Getting a Session
Section titled “Getting a Session”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".
Checking Current Session
Section titled “Checking Current Session”GET /api/auth/sessionReturns the currently authenticated user or 401 if no valid session exists.
| Role | Description |
|---|---|
admin | Full access — users, providers, models, settings |
member | Full chat access + import conversations |
readonly | View-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.
Error Handling
Section titled “Error Handling”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"] } ]}HTTP Status Codes
Section titled “HTTP Status Codes”| Code | Meaning |
|---|---|
200 | OK |
201 | Created |
204 | No Content |
400 | Bad Request (validation failure) |
401 | Unauthorized (missing/expired session) |
403 | Forbidden (insufficient role) |
404 | Not Found |
409 | Conflict |
413 | Request body too large (>50 MB) |
429 | Too Many Requests (rate limited) |
500 | Internal Server Error |
Rate Limiting
Section titled “Rate Limiting”Auth Endpoints (Login / Register)
Section titled “Auth Endpoints (Login / Register)”- Window: 15 minutes
- Max attempts: 5 per IP and per username
- Cleanup runs every 5 minutes
Per-Endpoint Limits
Section titled “Per-Endpoint Limits”| Endpoint | Limit |
|---|---|
| Chat completion | 20 requests / minute per user |
| Image generation | 5 requests / minute per user |
| File upload | 10 requests / minute per user |
| Ollama model pull | 3 requests / 5 minutes per user |
Global Body Size Limit
Section titled “Global Body Size Limit”All /api/* requests are rejected with 413 if Content-Length exceeds 50 MB.
Endpoints
Section titled “Endpoints”Manage user authentication and sessions.
Register
Section titled “Register”Register a new user. Only available when no users exist (first-user registration).
Endpoint:
POST /api/auth/registerAuthentication: None (public)
Request Body:
| Field | Type | Required | Constraints |
|---|---|---|---|
username | string | Yes | 3–50 characters |
password | string | Yes | 8–100 characters |
Example Request:
curl -X POST http://localhost:3001/api/auth/register \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "supersecret123"}' \ -c cookies.txtSuccess 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 taken429— Rate limit exceeded
Authenticate with username and password.
Endpoint:
POST /api/auth/loginAuthentication: None (public)
Request Body:
| Field | Type | Required |
|---|---|---|
username | string | Yes |
password | string | Yes |
Example Request:
curl -X POST http://localhost:3001/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "supersecret123"}' \ -c cookies.txtSuccess 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
Logout
Section titled “Logout”Destroy the current session and clear the session cookie.
Endpoint:
POST /api/auth/logoutAuthentication: Session cookie (optional — works even without one)
Example Request:
curl -X POST http://localhost:3001/api/auth/logout \ -b cookies.txtSuccess Response (200):
{ "success": true}Get Session
Section titled “Get Session”Check the current session and return user info.
Endpoint:
GET /api/auth/sessionAuthentication: Session cookie
Example Request:
curl http://localhost:3001/api/auth/session \ -b cookies.txtSuccess Response (200):
{ "user": { "id": 1, "username": "admin", "role": "admin" }, "session": { "expiresAt": 1782950400000 }}Not Logged In (401):
{ "user": null}Change Password
Section titled “Change Password”Change the authenticated user’s password. Invalidates all existing sessions.
Endpoint:
PUT /api/auth/change-passwordAuthentication: Session cookie
Request Body:
| Field | Type | Required | Constraints |
|---|---|---|---|
currentPassword | string | Yes | Must match current password |
newPassword | string | Yes | 8–100 characters |
Example Request:
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 incorrect400— Invalid input
CRUD operations for conversations. All chat endpoints require authentication and scope data to the authenticated user.
List Chats
Section titled “List Chats”Retrieve paginated chats for the current user (excludes archived and deleted).
Endpoint:
GET /api/chatsAuthentication: Session cookie
Query Parameters:
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 50 | 100 | Number of chats to return |
offset | integer | 0 | — | Pagination offset |
Example Request:
curl "http://localhost:3001/api/chats?limit=20&offset=0" \ -b cookies.txtSuccess 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 Chat
Section titled “Create Chat”Create a new empty chat.
Endpoint:
POST /api/chatsAuthentication: Session cookie
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | No | Custom chat ID (UUID, auto-generated if omitted) |
title | string | No | Initial title (auto-generated from first message) |
folder_id | string | No | Folder UUID to place chat in |
Example Request:
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}Get Chat
Section titled “Get Chat”Retrieve a single chat by ID.
Endpoint:
GET /api/chats/:chatIdAuthentication: Session cookie
Example Request:
curl http://localhost:3001/api/chats/abc-123 \ -b cookies.txtSuccess Response (200):
{ "id": "abc-123", "title": "Help with React hooks", "memoryDisabled": false, "createdAt": 1710000000000, "updatedAt": 1710000060000}Update Chat
Section titled “Update Chat”Update a chat’s title.
Endpoint:
PATCH /api/chats/:chatIdAuthentication: Session cookie
Request Body:
| Field | Type | Required | Constraints |
|---|---|---|---|
title | string | No | Max 200 characters |
Example Request:
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}Delete Chat
Section titled “Delete Chat”Soft-delete a chat (sets deleted_at, not permanently removed).
Endpoint:
DELETE /api/chats/:chatIdAuthentication: Session cookie
Example Request:
curl -X DELETE http://localhost:3001/api/chats/abc-123 \ -b cookies.txtSuccess Response (200):
{ "message": "Chat deleted successfully"}Pin Chat
Section titled “Pin Chat”Pin a chat to the top of the list.
Endpoint:
POST /api/chats/:chatId/pinAuthentication: Session cookie
Success Response (200):
{ "message": "Chat pinned successfully"}Unpin Chat
Section titled “Unpin Chat”Remove pin from a chat.
Endpoint:
DELETE /api/chats/:chatId/pinAuthentication: Session cookie
Success Response (200):
{ "message": "Chat unpinned successfully"}Archive Chat
Section titled “Archive Chat”Move a chat to the archive.
Endpoint:
POST /api/chats/:chatId/archiveAuthentication: Session cookie
Success Response (200):
{ "message": "Chat archived successfully"}Unarchive Chat
Section titled “Unarchive Chat”Restore a chat from the archive.
Endpoint:
DELETE /api/chats/:chatId/archiveAuthentication: Session cookie
Success Response (200):
{ "message": "Chat unarchived successfully"}Toggle Chat Memory
Section titled “Toggle Chat Memory”Enable or disable memory for a specific chat.
Endpoint:
PUT /api/chats/:chatId/memoryAuthentication: Session cookie
Request Body:
| Field | Type | Required |
|---|---|---|
disabled | boolean | Yes |
Example Request:
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}Messages
Section titled “Messages”Manage messages within a chat. All endpoints require authentication and scope to the chat owner.
List Messages
Section titled “List Messages”Retrieve paginated messages for a chat.
Endpoint:
GET /api/chats/:chatId/messagesAuthentication: Session cookie
Query Parameters:
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 200 | 500 | Number of messages to return |
offset | integer | 0 | — | Pagination offset |
Example Request:
curl "http://localhost:3001/api/chats/abc-123/messages?limit=50&offset=0" \ -b cookies.txtSuccess 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}Create Message
Section titled “Create Message”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/messagesAuthentication: Session cookie
Request Body:
| Field | Type | Required | Constraints |
|---|---|---|---|
id | string | No | Custom message ID (auto-generated if omitted) |
role | string | Yes | "user", "assistant", or "system" |
content | string | Yes | Max 100,000 characters |
model | string | No | Model ID (for assistant messages) |
fileIds | string[] | No | Array of file attachment IDs |
metadata | object | No | Arbitrary JSON metadata |
Example Request:
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}Delete Message
Section titled “Delete Message”Remove a single message from a chat.
Endpoint:
DELETE /api/chats/:chatId/messages/:messageIdAuthentication: Session cookie
Success Response (200):
{ "message": "Message deleted successfully"}Completion (Streaming)
Section titled “Completion (Streaming)”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/completionAuthentication: Session cookie
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model ID (e.g., "gpt-4o", "claude-sonnet-4-20250514") |
systemPromptId | string | No | System prompt template ID (default: "default") |
messages | array | Yes | Array of { id, role, content, fileIds? } objects |
fileIds | string[] | No | Legacy: file attachments for last user message |
webSearch | boolean | No | Enable web search tool (requires Brave API key + tool-supporting model) |
memoryEnabled | boolean | No | Enable memory extraction (default: true) |
Example Request:
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— Errorp— Partial text updated— Done (stream complete, includesfinishReasonandusage)
Possible Errors:
400— Invalid request body403— Invalid file attachments404— Chat not found429— Rate limit exceeded (20/min)500— Completion failed
Upload, manage, and download file attachments.
Upload File
Section titled “Upload File”Upload a file attachment.
Endpoint:
POST /api/filesAuthentication: 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:
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}List Files
Section titled “List Files”Retrieve all files for the current user.
Endpoint:
GET /api/filesAuthentication: Session cookie
Success Response (200):
{ "files": [ { "id": "f_abc123", "filename": "image.png", "size": 245760, "sizeFormatted": "240 KB", "mimeType": "image/png", "createdAt": 1710000000000 } ], "total": 1}Get File Metadata
Section titled “Get File Metadata”Retrieve metadata for a single file.
Endpoint:
GET /api/files/:idAuthentication: 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 File
Section titled “Download File”Download the raw file content.
Endpoint:
GET /api/files/:id/contentAuthentication: Session cookie
Response: Raw file bytes with Content-Type and Content-Disposition headers.
Example Request:
curl http://localhost:3001/api/files/f_abc123/content \ -b cookies.txt \ -o downloaded-image.pngNote: SVG files are served as attachment (not inline) to prevent stored XSS.
Delete File
Section titled “Delete File”Delete a file from disk and database.
Endpoint:
DELETE /api/files/:idAuthentication: Session cookie
Success Response (200):
{ "message": "File deleted successfully"}Folders
Section titled “Folders”Organize chats into folders.
List Folders
Section titled “List Folders”Endpoint:
GET /api/foldersAuthentication: 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 } ]}Get Folder
Section titled “Get Folder”Endpoint:
GET /api/folders/:idAuthentication: Session cookie
Get Folder Chats
Section titled “Get Folder Chats”Endpoint:
GET /api/folders/:id/chatsAuthentication: Session cookie
Success Response (200):
{ "chats": [ { "id": "chat-uuid", "title": "Chat in this folder", "folder_id": "folder-uuid", "created_at": 1710000000000, "updated_at": 1710000000000 } ]}Create Folder
Section titled “Create Folder”Endpoint:
POST /api/foldersAuthentication: Session cookie
Request Body:
| Field | Type | Required | Constraints |
|---|