Chat
The Chat API processes messages through the LVNG engine. Two endpoints are available: a synchronous endpoint that returns a complete response, and a streaming endpoint that delivers incremental text and tool events via Server-Sent Events. Both take images and file attachments.
Send Message
Send a message and wait for the complete response. Rate limited to 100 requests per minute per IP, and 30 requests per minute per user. Supports JWT or API key authentication.
/api/v2/chatAuthenticatedProcess a message through the LVNG engine and return a complete response. Takes file attachments, images, and a message type (chat, research, image, video).
Body Parameters
messagestringrequiredThe user message to process.
platformstring"api"Where the message comes from, for example api or web.
userIdstringUser ID for conversation context and per-user rate limiting.
channelIdstring (UUID)Channel UUID for conversation scoping. Messages are stored and retrieved by channel.
contextobjectAdditional context passed to the AI engine (tool results, metadata, prior state).
personalitystring"lvng"The id of a twin in your workspace to answer as. Leave it out for LVNG's own answer. The expert twin catalogue is not available.
streamingbooleanfalseReserved flag (use /api/v2/chat/stream for actual streaming).
modelstringA Claude model id to use instead of the chat model (claude-sonnet-5-5). Leave it out to use the chat model.
messageTypestring"chat"Routing hint: chat, research, image, or video. Research mode enables web search/scraping.
useFirecrawlbooleanfalseEnable web search and scraping for this request.
attachmentsarrayFile attachments as [{ id, name, type, size, url }]. Content is extracted and injected into the message context.
imagesarrayBase64-encoded images for Claude vision: [{ filename, mediaType, base64 }].
debugbooleanfalseEnable debug mode to include tool call traces in the response.
Request
curl -X POST https://api.lvng.ai/api/v2/chat \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Summarize the latest sales report",
"channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"platform": "api"
}'Response 200
{
"messageId": "7e6d5c4b-3a29-1098-7654-321fedcba098",
"reply": "Based on the latest sales report, Q1 revenue increased 23% year-over-year to $4.2M. Key highlights:\n\n- Enterprise segment grew 31% driven by 12 new accounts\n- Average deal size increased from $48K to $62K\n- Sales cycle shortened by 8 days on average",
"personality": "lvng",
"sessionId": "b8c9d0e1-f2a3-4b5c-6d7e-8f9012345678",
"timestamp": "2026-03-19T14:32:18.000Z",
"responseTime": 2340,
"attachments": [],
"confidence": null,
"metadata": {
"toolsUsed": [{ "name": "search_knowledge", "status": "success" }]
}
}Stream Response
Stream an AI response in real-time using Server-Sent Events. The connection stays open while the AI generates text and executes tools, then closes after the final done event. A keepalive comment is sent every 15 seconds to prevent proxy timeouts.
/api/v2/chat/streamAuthenticatedStream an AI response via Server-Sent Events. Returns Content-Type: text/event-stream.
Body Parameters
messagestringrequiredThe user message to process.
platformstring"api"Source platform identifier.
userIdstringUser ID for conversation context.
channelIdstring (UUID)Channel UUID. Conversation history is loaded from this channel (last 10 messages).
workspaceIdstring (UUID)Workspace context for the conversation.
threadIdstringThread ID for threaded conversations.
personalitystringThe id of a twin in your workspace to answer as. Leave it out for LVNG's own answer.
modelstringA Claude model id to use instead of the chat model (claude-sonnet-5-5).
contextobjectAdditional context passed to the AI engine.
imagesarrayBase64-encoded images for multi-modal input.
Request
curl -N -X POST https://api.lvng.ai/api/v2/chat/stream \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "Walk me through how OODA loops work in LVNG",
"channelId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}'Response 200
event: connected
data: {"streamId":"c4b3a291-0987-4543-81fe-dcba09876543","timestamp":"2026-10-13T14:35:00.000Z"}
event: tool_start
data: {"tool":"search_knowledge","toolId":"toolu_01A2b3C4","timestamp":"2026-10-13T14:35:01.000Z"}
event: tool_call
data: {"tool":"search_knowledge","input":{"query":"remote work policy core hours"}}
event: tool_result
data: {"tool":"search_knowledge","duration":420,"resultPreview":"remote-work-policy.pdf: Core hours are 10am-3pm..."}
event: tool_complete
data: {"tool":"search_knowledge","toolId":"toolu_01A2b3C4","success":true,"duration":420}
event: text_delta
data: {"content":"The policy sets core hours","accumulated_length":26}
event: text_delta
data: {"content":" from 10am to 3pm.","accumulated_length":44}
event: done
data: {"streamId":"c4b3a291-0987-4543-81fe-dcba09876543","reply":"The policy sets core hours from 10am to 3pm.","personality":"lvng","responseTime":3200,"toolsUsed":["search_knowledge"],"confidence":null,"metadata":{"toolsUsed":["search_knowledge"],"knowledgeGraphQueried":false}}SSE Event Types
The streaming endpoint emits the following event types. Your client should handle each type to provide a responsive user experience.
| Event | Description | Data Fields |
|---|---|---|
| connected | Initial heartbeat confirming the stream is open. | streamId, timestamp |
| text_delta | Incremental text content. Append to your buffer. | content, accumulated_length |
| tool_start | A tool invocation has begun. | tool, toolId, timestamp |
| tool_call | Tool input parameters (sent after tool_start). | tool, input |
| tool_result | Tool output preview (truncated to 200 chars). | tool, duration, resultPreview |
| tool_complete | Tool execution finished with success/failure status. | tool, toolId, success, duration |
| done | Stream complete. Contains the full reply and metadata. | streamId, reply, personality, responseTime, toolsUsed, confidence, metadata |
| error | An error occurred during processing. | message, streamId |
Client Example
A minimal TypeScript example that consumes the SSE stream, appends text deltas, and handles tool and completion events.
const response = await fetch('https://api.lvng.ai/api/v2/chat/stream', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: 'Summarize this week in the #general channel',
userId: 'f6a7b8c9-0d1e-2f3a-4b5c-6d7e8f901234',
channelId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
}),
})
const reader = response.body!.getReader()
const decoder = new TextDecoder()
let buffer = ''
let fullText = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true })
const lines = buffer.split('\n')
buffer = lines.pop() || ''
let currentEvent = ''
for (const line of lines) {
if (line.startsWith('event: ')) {
currentEvent = line.slice(7)
} else if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6))
switch (currentEvent) {
case 'connected':
console.log('Stream started:', data.streamId)
break
case 'text_delta':
fullText += data.content
process.stdout.write(data.content)
break
case 'tool_start':
console.log('\nTool started:', data.tool)
break
case 'tool_complete':
console.log('Tool done:', data.tool, data.duration + 'ms')
break
case 'done':
console.log('\n---')
console.log('Response time:', data.responseTime + 'ms')
console.log('Tools used:', data.toolsUsed)
break
case 'error':
console.error('Stream error:', data.message)
break
}
}
}
}