Chat completions
The /api/v1/chat/completions endpoint speaks the OpenAI shape, so most existing OpenAI client libraries work against an Exolvra bot by just changing base_url and api_key.
POST /api/v1/chat/completions
Accepts the standard OpenAI request body; returns the standard OpenAI response body with an additional exolvra extension object for bot-specific metadata.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
model | string | no | Ignored in favour of the bot’s configured model. Send "exolvra-bot" as a placeholder. |
messages | array | yes | Only role: "user" messages are used; assistant and system messages from prior turns are ignored (the server reconstructs history from the session). |
stream | bool | no | Default false. When true, responses are streamed as Server-Sent Events in the OpenAI chat.completion.chunk format. |
user | string | no | Strongly recommended. Stable identifier for the end-user conversation — used to thread multi-turn history into the same Exolvra session. Clients that don’t send this get a fresh session per request. |
Example — non-streaming
curl -X POST https://your-exolvra.example/api/v1/chat/completions \
-H "Authorization: Bearer exo_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"model": "exolvra-bot",
"messages": [
{"role": "user", "content": "How do I reset my password?"}
],
"user": "end-user-42",
"stream": false
}'
Response
{
"id": "chatcmpl-abc123...",
"object": "chat.completion",
"created": 1712700000,
"model": "claude-sonnet-4-6",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "To reset your password, go to Settings → Security → Reset Password..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 150,
"completion_tokens": 85,
"total_tokens": 235
},
"exolvra": {
"bot_id": "support-bot-abc123",
"session_id": "sess_xyz",
"cost_usd": 0.0032,
"conversation_starters": [
"How do I reset my password?",
"Where is my billing history?"
]
}
}
The exolvra.conversation_starters field is only populated on the first turn of a session — subsequent turns return an empty array so your client can stop rendering the chip row.
Streaming
curl -N -X POST https://your-exolvra.example/api/v1/chat/completions \
-H "Authorization: Bearer exo_..." \
-H "Content-Type: application/json" \
-d '{"model":"exolvra-bot","messages":[{"role":"user","content":"Hello"}],"stream":true}'
The server responds with SSE chunks matching chat.completion.chunk, terminated by data: [DONE].
GET /api/v1/bots/me
Returns metadata for the bot the calling API key is bound to. The embeddable widget calls this on load to render the header and starter chips.
curl https://your-exolvra.example/api/v1/bots/me \
-H "Authorization: Bearer exo_..."
Response:
{
"id": "support-bot-abc123",
"name": "Support Assistant",
"description": "Friendly customer support bot",
"icon": "🛠",
"conversationStarters": [
"How do I reset my password?",
"I'm having trouble logging in"
],
"hasKnowledge": true,
"model": "claude-sonnet-4-6"
}
hasKnowledge indicates whether the bot has a RAG-backed document collection attached.
Sessions
GET /api/v1/sessions
Lists sessions started by this API key. Useful for building a “recent conversations” UI on a customer dashboard.
curl https://your-exolvra.example/api/v1/sessions \
-H "Authorization: Bearer exo_..."
{
"sessions": [
{
"id": "sess_abc",
"channelId": "bot-api:key-id:end-user-42",
"createdAt": "2026-04-10T14:32:00Z",
"lastActivityAt": "2026-04-10T14:35:21Z"
}
]
}
Sessions are filtered to only those owned by the calling key — keys cannot see each other’s conversations.
GET /api/v1/sessions/{id}
Fetch a specific session by id. Returns 404 if the session doesn’t exist or belongs to a different key.
DELETE /api/v1/sessions/{id}
Terminate a session. Useful when a customer wants to “start over” — the next message with the same user field will land in a fresh session.
Using OpenAI SDKs
Python
from openai import OpenAI
client = OpenAI(
api_key="exo_a1b2c3d4e5f6...",
base_url="https://your-exolvra.example/api/v1",
)
response = client.chat.completions.create(
model="exolvra-bot",
messages=[{"role": "user", "content": "How do I reset my password?"}],
user="end-user-42",
)
print(response.choices[0].message.content)
TypeScript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "exo_a1b2c3d4e5f6...",
baseURL: "https://your-exolvra.example/api/v1",
});
const response = await client.chat.completions.create({
model: "exolvra-bot",
messages: [{ role: "user", content: "How do I reset my password?" }],
user: "end-user-42",
});
console.log(response.choices[0].message.content);
Vercel AI SDK
import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";
const exolvra = createOpenAI({
apiKey: process.env.EXOLVRA_KEY!,
baseURL: "https://your-exolvra.example/api/v1",
});
const { text } = await generateText({
model: exolvra("exolvra-bot"),
prompt: "How do I reset my password?",
});
LangChain (Python)
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="exolvra-bot",
openai_api_key="exo_...",
openai_api_base="https://your-exolvra.example/api/v1",
)
result = llm.invoke("How do I reset my password?")
print(result.content)