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(),
}))