Introduction
Everything you need to make your first request to the Xpectrum API.
Base URL
https://cloud.xpectrum.dev/v1All endpoints in these docs are relative to this base URL. The chat endpoints are OpenAI-compatible, so any OpenAI SDK works by pointing its base_url here.
Authentication
Every request is authenticated with a Bearer token in the Authorization header:
Authorization: Bearer xpectrum_XXXXXXXXXXXXXXXX- App API key (
xpectrum_...) — scoped to a single agent. Used by every endpoint. Create one in the Xpectrum console under your app's API Access page.
⚠ Where to keep your key
The user identifier
Most endpoints accept a user field — a stable identifier you choose for your end user (for example your own user ID). Conversations (threads) are stored per user, so passing the same value on every request is what makes history and multi-turn memory line up. Chat endpoints take it in the JSON body; thread listing takes it as a query parameter.
How to pick the value:
- Your app has login — use the logged-in user's id from your own system. Their conversation history follows them across devices.
- No login (anonymous visitors) — generate a random id once per browser and reuse it (e.g. store it in
localStorage). Each visitor then has their own private history, and nobody can see anyone else's conversations.
Quick start
Send your first message with curl:
curl https://cloud.xpectrum.dev/v1/chat/completions \
-H "Authorization: Bearer xpectrum_XXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"messages": [{ "role": "user", "content": "Hello!" }],
"stream": true,
"user": "user-123"
}'The reply streams back as SSE chunks. Streaming works for every app type — Autonomous Agent apps reject non-streaming requests — so it is the right default for a first call.
Or use the official OpenAI SDK — only the base URL and key change:
from openai import OpenAI
client = OpenAI(
base_url="https://cloud.xpectrum.dev/v1",
api_key="xpectrum_XXXXXXXXXXXXXXXX",
)
stream = client.chat.completions.create(
model="my-app", # any string; the key already selects the app
messages=[{"role": "user", "content": "Hello!"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://cloud.xpectrum.dev/v1",
apiKey: "xpectrum_XXXXXXXXXXXXXXXX",
});
const response = await client.chat.completions.create({
model: "my-app",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);Or use the Xpectrum SDK, which speaks this API natively and handles streaming and conversation state for you:
npm install xpectrumimport { XpectrumChat } from "xpectrum";
const chat = new XpectrumChat({
baseUrl: "https://cloud.xpectrum.dev/v1",
apiKey: "xpectrum_XXXXXXXXXXXXXXXX",
user: "user-123",
});
const res = await chat.send("Hello!");
console.log(res.content);ℹ Building a web UI?
Endpoints at a glance
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /chat/completions | Talk to an AI Chatbot, Autonomous Agent, or Agent Flow app (OpenAI-compatible) |
| GET | /models | The agent behind your API key — name, greeting, starter questions (OpenAI-compatible) |
| GET | /threads | List a user's threads |
| GET | /threads/{thread_id}/messages | Fetch one thread's transcript |
| GET | /messages/{message_id}/suggestions | Follow-up questions for a reply |
| POST | /voice/tokens/generate | Start a voice call — exchanges the API key for a LiveKit room token |
| POST | /voice/call-control/end-call | End an active voice call |
| POST | /runs | Execute a Workflow app |
| POST | /runs/{run_id}/cancel | Stop an in-flight generation or run |
ℹ App modes
/runs. Calling the wrong one returns a 404 with code model_not_found.