Skip to Content
API ReferenceWebSocket

WebSocket

Nexora streams agent responses over WebSocket. Connect once per chat session.

Connect

wss://your-nexora-instance.com/api/ws/{chat_id}?token=<access_token>

Obtain an access_token via the login endpoint:

POST /api/auth/login Content-Type: application/json { "email": "user@example.com", "password": "password" }

The token query param accepts either a JWT access token (from the login endpoint) or an API key (nxr_...). Pass whichever you have — both authenticate the WebSocket connection.

Client → Server

Send message

{ "type": "message", "content": "What is the status of the deployment?", "client_message_id": "unique-client-id" }

client_message_id is used for deduplication — safe to retry on disconnect.

Ping

{ "type": "ping" }

Server replies with { "type": "pong" }.

Server → Client

Chunk (streaming text)

{ "type": "chunk", "message_id": "uuid", "content": "Partial response text..." }

Tool call

{ "type": "tool_call", "tool": "github", "input": { "action": "list_issues", "repo": "owner/repo" } }

Tool result

{ "type": "tool_result", "tool": "github", "result": { "issues": [] } }

Sub-agent events

{ "type": "sub_agent_start", "task_id": "uuid", "agent_name": "Research Assistant" } { "type": "sub_agent_complete", "task_id": "uuid", "result": "..." }

Done

{ "type": "done", "message_id": "uuid" }

Response complete. Message saved to the database.

Error

{ "type": "error", "code": "all_providers_exhausted", "message": "All LLM providers failed" }

Duplicate

{ "type": "duplicate", "client_message_id": "your-id", "message_id": "uuid" }

client_message_id already processed — the existing message_id is returned.

Reconnection

Implement exponential backoff with jitter:

let attempt = 0 function connect(chatId, token) { const ws = new WebSocket( `wss://nexora.example.com/api/ws/${chatId}?token=${token}` ) ws.onopen = () => { attempt = 0 } ws.onclose = () => { const delay = Math.min(1000 * 2 ** attempt + Math.random() * 1000, 30000) attempt++ setTimeout(() => connect(chatId, token), delay) } ws.onmessage = (event) => { const msg = JSON.parse(event.data) handleMessage(msg) } return ws }

Full example

Get a token and create a chat

const { access_token } = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'user@example.com', password: 'password' }), }).then(r => r.json()) const { id: chatId } = await fetch('/api/chats', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${access_token}`, }, body: JSON.stringify({ agent_id: 'your-agent-uuid' }), }).then(r => r.json())

Connect and listen

const ws = new WebSocket( `wss://nexora.example.com/api/ws/${chatId}?token=${access_token}` ) ws.onmessage = (event) => { const msg = JSON.parse(event.data) if (msg.type === 'chunk') process.stdout.write(msg.content) if (msg.type === 'done') console.log('\n[done]') if (msg.type === 'error') console.error(msg.message) }

Send a message

ws.send(JSON.stringify({ type: 'message', content: 'Review the latest deployment logs', client_message_id: crypto.randomUUID(), }))