Skip to content

API & protocol reference

Xiajiao splits traffic: HTTP for CRUD, WebSocket for realtime delivery.

HTTP API

Authentication

Except login, send the session cookie on every request:

Cookie: session=<token>

Obtain the token via POST /api/login.

Auth endpoints

POST /api/login

json
// Request
{ "password": "your-owner-key" }

// 200
{ "ok": true }
// Set-Cookie: session=<token>; HttpOnly; SameSite=Strict

// 401
{ "error": "Invalid password" }

POST /api/logout

json
// 200
{ "ok": true }

Messages

GET /api/messages?channelId=<id>&limit=50&before=<msgId>

json
// 200
{
  "messages": [
    {
      "id": "msg_xxx",
      "channelId": "ch_xxx",
      "agentId": "agent_xxx",
      "userId": "user_xxx",
      "content": "Message text",
      "type": "text",
      "metadata": {},
      "createdAt": "2026-03-24T10:00:00Z"
    }
  ]
}

POST /api/messages

json
// Request
{
  "channelId": "ch_xxx",
  "content": "@Novelist write a short poem",
  "type": "text"
}

// 200
{ "id": "msg_xxx", "ok": true }

Agents

GET /api/agents

json
// 200
{
  "agents": [
    {
      "id": "agent_xxx",
      "name": "Xiajiao Butler",
      "avatar": "🤖",
      "description": "Housekeeping assistant for Xiajiao IM",
      "model": "gpt-4o",
      "tools": ["web_search", "memory_write", "memory_search"],
      "status": "online"
    }
  ]
}

GET /api/agents/:id

Agent detail including SOUL.md body.

PUT /api/agents/:id

json
// Request
{
  "name": "New name",
  "model": "claude-sonnet",
  "tools": ["web_search", "rag_query"]
}

POST /api/agents

Create agent.

Channels / groups

GET /api/channels

List channels.

POST /api/channels

json
// Request
{
  "name": "Writing studio",
  "type": "group",
  "agentIds": ["agent_1", "agent_2"]
}

PUT /api/channels/:id

Update channel.

POST /api/channels/:id/members

Add members.

Settings

GET /api/settings

PUT /api/settings

Update models, keys, etc.

RAG

POST /api/rag/upload

bash
curl -X POST http://localhost:18800/api/rag/upload \
  -H "Cookie: session=<token>" \
  -F "file=@document.pdf" \
  -F "agentId=agent_xxx"

POST /api/rag/query

json
// Request
{
  "agentId": "agent_xxx",
  "query": "What is the deployment process?",
  "topK": 5
}

Uploads

POST /api/upload

bash
curl -X POST http://localhost:18800/api/upload \
  -H "Cookie: session=<token>" \
  -F "file=@image.png"
json
// 200
{ "url": "/uploads/2026-03/image-xxx.png" }

WebSocket protocol

Connect

javascript
const ws = new WebSocket('ws://localhost:18800/ws');

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'auth',
    token: sessionToken
  }));
};

Envelope

json
{
  "type": "message-type",
  "data": { }
}

Client → server

auth

json
{ "type": "auth", "token": "session-token" }

ping

json
{ "type": "ping" }

subscribe

json
{ "type": "subscribe", "channelId": "ch_xxx" }

Server → client

auth_ok

json
{ "type": "auth_ok", "userId": "user_xxx" }

pong

json
{ "type": "pong" }

message

json
{
  "type": "message",
  "data": {
    "id": "msg_xxx",
    "channelId": "ch_xxx",
    "agentId": "agent_xxx",
    "content": "Full message body",
    "type": "text",
    "createdAt": "2026-03-24T10:00:00Z"
  }
}

stream_start / stream_chunk / stream_end

json
{ "type": "stream_start", "data": { "messageId": "msg_xxx", "channelId": "ch_xxx", "agentId": "agent_xxx" } }
json
{ "type": "stream_chunk", "data": { "messageId": "msg_xxx", "content": "token slice" } }
json
{ "type": "stream_end", "data": { "messageId": "msg_xxx" } }

tool_call / tool_result

json
{
  "type": "tool_call",
  "data": {
    "messageId": "msg_xxx",
    "toolName": "web_search",
    "arguments": { "query": "Node.js 22 features" },
    "status": "calling"
  }
}
json
{
  "type": "tool_result",
  "data": {
    "messageId": "msg_xxx",
    "toolName": "web_search",
    "result": "Search results…"
  }
}

collab_status

json
{
  "type": "collab_status",
  "data": {
    "chainId": "chain_xxx",
    "currentAgent": "agent_xxx",
    "step": 2,
    "totalSteps": 3,
    "status": "running"
  }
}

Database schema

Main DB: data/xiajiao.db (SQLite).

Core tables

TablePurpose
usersUsers
channelsChannels / groups
channel_membersMembership
messagesMessages
agentsAgent rows (also agents.json)
settingsSettings + model keys
sessionsLogin sessions

Per-agent memory

Path: data/workspace-{agentId}/memory.db

TablePurpose
memoriesMemory rows
memory_embeddingsVectors for semantic search

Per-agent RAG

Path: data/workspace-{agentId}/rag/rag.db

TablePurpose
documentsDocument metadata
chunksChunks
chunk_embeddingsEmbeddings
chunk_ftsFTS5 index

HTTP status codes

CodeMeaningTypical cause
200OK
400Bad requestMissing fields, bad JSON
401UnauthorizedNot logged in, expired session
403ForbiddenGuest hitting admin APIs
404Not foundBad channel/agent/message id
429Too many requestsRate limit
500Server errorLLM failure, DB error

curl quick test

Login

bash
curl -c cookies.txt -X POST http://localhost:18800/api/login \
  -H "Content-Type: application/json" \
  -d '{"password":"admin"}'

List agents

bash
curl -b cookies.txt http://localhost:18800/api/agents | python3 -m json.tool

Send message

bash
curl -b cookies.txt -X POST http://localhost:18800/api/messages \
  -H "Content-Type: application/json" \
  -d '{"channelId":"ch_xxx","content":"@Code assistant hello","type":"text"}'

Fetch history

bash
curl -b cookies.txt "http://localhost:18800/api/messages?channelId=ch_xxx&limit=10"

TIP

-c cookies.txt stores cookies; -b cookies.txt sends them so commands share the session.

WebSocket debugging

bash
npm install -g wscat
wscat -c "ws://localhost:18800/ws" -H "Cookie: session=your-token"
> {"type":"auth","token":"your-session-token"}
< {"type":"auth_ok","userId":"user_xxx"}
> {"type":"subscribe","channelId":"ch_xxx"}