Your content, your AI,
anywhere you need it.
The AskCybex API is OpenAI-compatible. Anything already built for that format works by changing a base URL and a key — no SDK, no rewrite. Connect a CMS, a custom web app, an internal tool, an ERP or a mobile app to a chatbot trained on your own documents.
1 Get your API key
An API key maps to exactly one deployment — one chatbot trained on one set of documents. The key alone decides which documents an answer can come from, so you never pass a deployment id separately.
- Create a deployment and train it In your dashboard go to Document Training, create a deployment, upload your files (PDF, DOCX, TXT, CSV) and click Train. Wait for the status to reach Completed.
- Open the API key page Go to API key in the sidebar, or click here if you're signed in.
- Generate a key for that deployment Each deployment gets its own key. Copy it immediately — it is stored hashed, so it cannot be shown again. If you lose it, delete the key and generate a new one.
- Keep it server-side where you can A key spends your token balance. Our chat widget uses it in the browser by necessity — if you do the same, restrict the deployment by IP in Settings → IP Restriction and watch usage under Reports.
2 Authentication
Send your key whichever way suits the client. All three are equivalent:
Authorization: Bearer YOUR_API_KEY # preferred, used by /api/v1/*
X-API-KEY: YOUR_API_KEY # header alternative
?api_key=YOUR_API_KEY # query/form field — required for SSE,
# because EventSource cannot set headers
Keys are stored as SHA-256 hashes. An invalid or disabled key, or a deployment
that is not published, returns 401.
3 Quickstart
Ask your first question in one request. Pick a language:
curl https://askcybex.com/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_DEPLOYMENT_ID",
"messages": [
{ "role": "user", "content": "What is your refund policy?" }
]
}'
// Works with the official OpenAI SDK — only the baseURL changes.
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://askcybex.com/api/v1",
});
const res = await client.chat.completions.create({
model: "YOUR_DEPLOYMENT_ID",
messages: [{ role: "user", content: "What is your refund policy?" }],
});
console.log(res.choices[0].message.content);
# pip install openai
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://askcybex.com/api/v1",
)
res = client.chat.completions.create(
model="YOUR_DEPLOYMENT_ID",
messages=[{"role": "user", "content": "What is your refund policy?"}],
)
print(res.choices[0].message.content)
$ch = curl_init('https://askcybex.com/api/chat/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => http_build_query([
'api_key' => 'YOUR_API_KEY',
'msg' => 'What is your refund policy?',
'conversation_id' => 'visitor-123',
]),
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data['response'] ?? $data['error'];
Multi-turn conversations
Follow-up questions need the earlier turns. Pick one of two styles — don't mix them.
id starts with chatcmpl- and identifies that single completion.
conversation_id starts with conv- and identifies the thread.
Only conversation_id continues a conversation — passing the
chatcmpl- id starts a brand new, empty thread, and the bot will appear to have
forgotten everything.
Style A — resend the messages (OpenAI-native). Stateless, and what the OpenAI SDKs and Open WebUI do automatically:
{
"model": "98",
"messages": [
{ "role": "user", "content": "What is Hogwarts?" },
{ "role": "assistant", "content": "Hogwarts is a school of witchcraft and wizardry..." },
{ "role": "user", "content": "Who are the students there?" }
]
}
Style B — reuse the conversation id. Send only the new question; we rebuild the history server-side:
# Turn 1 — no id sent, so one is minted and returned
curl -X POST https://askcybex.com/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"model":"98","messages":[{"role":"user","content":"What is Hogwarts?"}]}'
# response contains BOTH ids — copy the conv- one:
# "id": "chatcmpl-f616e6134ae341316ba712a9" <- NOT this
# "conversation_id": "conv-dc4d05c139d35b910ff4be69" <- this one
# Turn 2 — reuse conversation_id, send only the new question
curl -X POST https://askcybex.com/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"model":"98",
"messages":[{"role":"user","content":"Who are the students there?"}],
"conversation_id":"conv-dc4d05c139d35b910ff4be69"}'
If you send both, the messages history wins, so a turn is
never counted twice. Both styles work identically on
/chat/completions-with-sources.
/chat/completions and /chat/completions-with-sources the document
search uses your question exactly as typed — history reaches the model that writes the
answer, but not the search. So “and who are they?” searches for those
literal words and usually finds nothing.
Two ways to fix it: keep the subject in the question (“who are the students at Hogwarts?”), or send the turn to
/api/v1/chat/completions-contextual, which resolves the follow-up against the
conversation before searching and tells you what it searched for.
4 Endpoint reference
Two families. Use /api/v1 when you want drop-in OpenAI compatibility, and the native endpoints when you want streaming, FAQ data or feedback.
OpenAI-compatible
/api/v1/modelsReturns the deployment your key maps to, as an OpenAI model object. Clients such as
Open WebUI call this to fill their model picker. The id it returns is what
you pass as model.
/api/v1/chat/completionsAnswers the last user message from your documents, in the standard ChatCompletion shape.
Earlier messages are used as history. Supports stream, temperature
and max_tokens.
/api/v1/chat/completions-with-sources
citationsIdentical, plus a sources array naming the documents behind the answer.
Use it when you must show citations or audit where an answer came from.
/api/v1/chat/completions-contextual
best for multi-turnSearches your documents with a history-aware query. The other endpoints search using
the question exactly as typed, so a follow-up like “who are the students
there?” is searched literally and usually matches nothing. This one resolves it to
“who are the students at Hogwarts?” first, searches with that, then
answers in your original wording. Returns search_query so you can see what was
searched, plus the same sources as above.
The retrieved passages (chunks) are
opt-in here — send "include_chunks": true if you need them. They are
verbatim text from your documents and can add tens of KB to every turn, so a chat UI that
only shows document names should leave them off.
Costs one extra small model call per turn, and only when there is history to resolve — a first question costs the same as the others.
Native REST
/api/chat/
60 / minSend a message, get the full answer. Pass the same conversation_id on every
turn so follow-ups like “how much does that cost?” resolve correctly. Returns
chat_log_id, which you use to attach feedback.
api_keyrequired — your deployment keymsgrequired — the visitor questionconversation_idthread id, reused across turnsvisitor_emailcaptured lead email, stored on the log/api/stream/
SSE60 / minThe same answer, streamed token by token over Server-Sent Events so it appears as it is
written. The key goes in the query string because EventSource cannot set headers.
const es = new EventSource(
"https://askcybex.com/api/stream/?api_key=YOUR_API_KEY" +
"&msg=" + encodeURIComponent(question) +
"&conversation_id=" + conversationId
);
es.onmessage = (e) => {
const d = JSON.parse(e.data);
if (d.token) output.textContent += d.token; // stream in
if (d.error) console.error(d.error);
if (d.done) { es.close(); rate(d.chat_log_id); }
};
/api/faq/details/
120 / minReturns the deployment name and any pre-generated question/answer pairs — handy for rendering an FAQ block or suggesting questions before the visitor types.
/api/feedback/
120 / minRecord whether an answer helped. Send chat_log_id and
feedback (1 = helpful, 0 = not). Ratings show up in
your dashboard next to the question that produced them.
5 Use it inside tools you already run
Because the API speaks the OpenAI format, most AI tooling connects without any code. For Open WebUI:
- Settings → Connections → OpenAI APIAdd a new connection.
- Base URL
https://askcybex.com/api/v1 - API keyYour deployment key.
- Save, then pick your deployment from the model listIt appears by deployment id.
The same pattern works for LangChain, LlamaIndex, agent frameworks, ERP and CRM add-ons, and any internal tool that lets you set an OpenAI base URL.
6 Rate limits, errors & billing
| Endpoint | Limit |
|---|---|
/api/chat/, /api/stream/, /api/v1/chat/* | 60 requests / minute |
/api/faq/details/, /api/feedback/, /api/openapi.json | 120 requests / minute |
Every response carries X-RateLimit-Limit and
X-RateLimit-Remaining. Exceeding a limit returns 429.
| Status | Meaning | What to do |
|---|---|---|
401 | Invalid or disabled key, or the deployment isn't published | Check the key; publish the deployment |
402 | Token balance exhausted | Top up your balance |
404 | Deployment not found | Confirm the key belongs to a trained deployment |
429 | Rate limited | Back off and retry |
/api/chat/ and /api/faq/details/
answer HTTP 200 with an error field rather than an error status —
the WordPress plugins have relied on that since launch and we will not break it. Always
check for an error key, not just the status code. The
/api/v1 endpoints use proper status codes.
Billing. Answers consume tokens from your account balance. When a question cannot be grounded in your documents, the refusal is returned before the language model is called — so a “Sorry, I don’t know” costs you nothing.
Try every endpoint in the browser
The explorer is loaded with the live spec. Click Authorize, paste your key, and send real requests against your own deployment.