API: Chat Completions
OpenAI-kompatibler Chat-Completions-Endpunkt von Kasimir mit Bearer-API-Key, Streaming, Modell-Governance und Usage-Abrechnung.
Die Kasimir Public API stellt unter https://kasimir.ai/api/v1 eine OpenAI-kompatible Schnittstelle bereit. Der Endpunkt POST /api/v1/chat/completions nimmt denselben Request-Body wie die OpenAI Chat Completions API entgegen, leitet ihn transparent an die hinterlegte LLM-Infrastruktur (LiteLLM-Proxy) weiter und reichert ihn um Kasimir-spezifische Governance an: Authentifizierung per Firmen-API-Key, EU-Hosting-Gate pro Modell, Monats-Budget-Durchsetzung und Token-genaues Usage-Metering. Weil Wire-Format und Fehlerschema OpenAI entsprechen, funktionieren bestehende OpenAI-SDKs ohne Code-Änderung — es genügt, base_url und api_key zu setzen.
Endpunkt
Methode |
|
URL |
|
Auth |
|
Benötigter Scope |
|
Content-Type |
|
Antwort |
|
Authentifizierung
Alle Aufrufe werden über einen Firmen-API-Key authentifiziert, der im Header Authorization: Bearer <secret> mitgesendet wird. Keys haben das Format kasi_<32-Zeichen> und werden in der Kasimir-Oberfläche unter Verwaltung → Zugriff von Workspace-Ownern oder -Admins erzeugt.
Der Klartext-Key wird genau einmal bei der Erstellung angezeigt. Kasimir speichert nur einen SHA-256-Hash; ein verlorener Key kann nicht wiederhergestellt, nur widerrufen und neu erstellt werden.
Jeder Key trägt Scopes. Neu erstellte Keys erhalten standardmäßig chat:read und chat:write. Für Chat Completions ist chat:write erforderlich — fehlt der Scope, antwortet die API mit 403.
# Schlägt mit 401 fehl, wenn der Header fehlt oder der Key ungültig/widerrufen ist.
Authorization: Bearer kasi_abcdef0123456789abcdef0123456789Jeder erfolgreiche Aufruf aktualisiert das Feld last_used_at des Keys (nicht-blockierend), sodass sich ungenutzte Keys in der Verwaltung erkennen lassen.
Request-Body
Der Body folgt exakt dem OpenAI-Schema. Pflichtfelder werden validiert; alle weiteren Felder werden unverändert an die Upstream-Infrastruktur durchgereicht (Volle Parität: temperature, top_p, tools, tool_choice, response_format, stop, seed, max_tokens …).
Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
|
| ja | Kasimir-Modell-Slug (siehe „Modelle"). Nicht der OpenAI-Modellname. |
|
| ja | Mindestens 1 Nachricht im OpenAI-Chat-Format ( |
|
| nein |
|
| div. | nein | Werden 1:1 durchgereicht. |
Im Streaming-Modus setzt Kasimir serverseitig automatisch stream_options: { include_usage: true }, damit am Stream-Ende ein Usage-Chunk geliefert und das Metering korrekt verbucht wird — du musst das nicht selbst angeben.
Modelle
model erwartet einen Kasimir-Slug, keinen Upstream-Modellnamen. Slugs unterliegen derselben Governance wie der In-App-Modell-Picker:
Das Modell muss für deine Firma aktiv und vom Typ
chatsein.Per Workspace deaktivierte Modelle (
disabled_model_slugs) sind nicht aufrufbar →404.Nicht-EU-gehostete Modelle sind nur verfügbar, wenn deine Organisation
allow_non_eu_modelsaktiviert hat → sonst403.
Die für deinen Key gültigen Slugs listet GET /api/v1/models auf (siehe unten). Die Antwort gibt im model-Feld stets den Kasimir-Slug zurück, nicht die interne Upstream-ID.
Antwort (synchron)
Bei stream: false (oder ausgelassenem stream) ist die Antwort ein vollständiges OpenAI-Chat-Completion-Objekt. Das model-Feld wird auf den Kasimir-Slug normalisiert.
{
"id": "chatcmpl-…",
"object": "chat.completion",
"created": 1750000000,
"model": "self-hosted-llama-3.3-70b",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Hallo! Wie kann ich helfen?" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 18, "completion_tokens": 9, "total_tokens": 27 }
}Antwort (Streaming)
Bei stream: true antwortet der Endpunkt mit Content-Type: text/event-stream und re-emittiert den Upstream-SSE-Stream transparent — Format identisch zu OpenAI (data: {…}-Zeilen, abschließend data: [DONE]). Kasimir schreibt dabei nur das model-Feld jedes Chunks auf den Slug um und liest den finalen Usage-Chunk fürs Metering aus.
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","model":"self-hosted-llama-3.3-70b","choices":[{"index":0,"delta":{"role":"assistant","content":"Hallo"},"finish_reason":null}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","model":"self-hosted-llama-3.3-70b","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":9,"total_tokens":27}}
data: [DONE]Budget & Usage-Metering
Jeder Aufruf wird vor der Weiterleitung gegen das Monats-Budget der Firma geprüft. Ist ein monthly_budget_eur gesetzt und der aufsummierte Verbrauch des laufenden Kalendermonats (API und In-App-Chat zusammen) erreicht/übersteigt es, antwortet die API mit 402. Ein Budget von null oder ≤ 0 bedeutet unbegrenzt.
Nach jedem Aufruf wird ein Eintrag in das Usage-Ledger geschrieben: Modell-Slug, Endpunkt, Prompt-/Completion-Tokens und die berechneten EUR-Kosten. Beim Streaming geschieht dies, sobald der Stream endet (auch bei vorzeitigem Abbruch werden die bis dahin gezählten Tokens verbucht). Metering ist „best-effort" und bricht eine Antwort nie ab.
Kosten = (prompt_tokens / 1000) × Preis_input + (completion_tokens / 1000) × Preis_output, gerundet auf 6 Nachkommastellen, in EUR. Die Preise stammen aus der Modellkonfiguration.
Fehler
Fehler werden im OpenAI-Fehlerschema zurückgegeben, damit Standard-SDKs sie normal verarbeiten:
{ "error": { "message": "Missing scope: chat:write", "type": "permission_error", "code": null } }HTTP-Status |
| Bedeutung |
|---|---|---|
|
| Body ungültig (fehlendes |
|
| Bearer-Token fehlt, Key unbekannt oder widerrufen. |
|
| Monats-Budget der Firma erreicht. |
|
| Scope |
|
| Modell-Slug unbekannt, inaktiv oder workspace-deaktiviert. |
|
| Upstream-/Infrastrukturfehler. |
Tritt ein Fehler während eines bereits begonnenen Streams auf, kann er nicht mehr in das JSON-Fehlerschema umgewandelt werden — die Verbindung bricht ab. Behandle Stream-Abbrüche client-seitig.
Beispiele
curl — synchron
curl https://kasimir.ai/api/v1/chat/completions \
-H "Authorization: Bearer $KASIMIR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "self-hosted-llama-3.3-70b",
"messages": [
{ "role": "system", "content": "Du bist ein hilfreicher Assistent." },
{ "role": "user", "content": "Schreibe einen Einzeiler über Datenschutz." }
],
"temperature": 0.7
}'curl — Streaming
curl -N https://kasimir.ai/api/v1/chat/completions \
-H "Authorization: Bearer $KASIMIR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "self-hosted-llama-3.3-70b",
"messages": [{ "role": "user", "content": "Zähle von 1 bis 5." }],
"stream": true
}'Python — OpenAI SDK (synchron)
Da Kasimir OpenAI-kompatibel ist, genügt es, base_url und api_key zu setzen.
from openai import OpenAI
client = OpenAI(
base_url="https://kasimir.ai/api/v1",
api_key="kasi_…", # dein Kasimir-API-Key
)
resp = client.chat.completions.create(
model="self-hosted-llama-3.3-70b",
messages=[
{"role": "system", "content": "Du bist ein hilfreicher Assistent."},
{"role": "user", "content": "Nenne drei Vorteile von EU-Hosting."},
],
temperature=0.7,
)
print(resp.choices[0].message.content)
print(resp.usage) # prompt_tokens / completion_tokens / total_tokensPython — OpenAI SDK (Streaming)
from openai import OpenAI
client = OpenAI(base_url="https://kasimir.ai/api/v1", api_key="kasi_…")
stream = client.chat.completions.create(
model="self-hosted-llama-3.3-70b",
messages=[{"role": "user", "content": "Erkläre RAG in zwei Sätzen."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content if chunk.choices else None
if delta:
print(delta, end="", flush=True)
print()Fehlerbehandlung (Python)
from openai import OpenAI, APIStatusError
client = OpenAI(base_url="https://kasimir.ai/api/v1", api_key="kasi_…")
try:
client.chat.completions.create(
model="self-hosted-llama-3.3-70b",
messages=[{"role": "user", "content": "Hi"}],
)
except APIStatusError as e:
if e.status_code == 402:
print("Monats-Budget erreicht — bitte Budget erhöhen.")
elif e.status_code in (401, 403):
print("Auth/Scope-Problem:", e.message)
else:
raiseVerwandte Endpunkte
Dieselbe Authentifizierung, Governance und dasselbe Metering gelten für:
Endpunkt | Zweck |
|---|---|
| OpenAI-kompatible Liste der für deine Firma erlaubten Chat- und Embedding-Modelle ( |
| OpenAI-kompatible Embeddings ( |
| Führt einen konfigurierten Kasimir-Assistenten per API aus. |
curl https://kasimir.ai/api/v1/models \
-H "Authorization: Bearer $KASIMIR_API_KEY"