Kasimir Docs DEEN Zur App →

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

POST

URL

https://kasimir.ai/api/v1/chat/completions

Auth

Authorization: Bearer kasi_…

Benötigter Scope

chat:write

Content-Type

application/json

Antwort

application/json (sync) oder text/event-stream (Streaming)

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_abcdef0123456789abcdef0123456789
ℹ️

Jeder 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

model

string

ja

Kasimir-Modell-Slug (siehe „Modelle"). Nicht der OpenAI-Modellname.

messages

array

ja

Mindestens 1 Nachricht im OpenAI-Chat-Format ({ role, content, … }).

stream

boolean

nein

true → Server-Sent-Events-Stream. Default false.

temperature, top_p, max_tokens, stop, tools, tool_choice, response_format, seed, …

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 chat sein.

  • 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_models aktiviert hat → sonst 403.

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]
Chat Completions request flow POST /api/v1/chat/completions · governance gateway Client curl / OpenAI SDK POST /chat/ completions Bearer kasi_… request Kasimir gateway governance gates 1 Authenticate API key verify scope chat:write 2 Resolve model slug EU sovereignty gate 3 Assert monthly budget spend cap not exceeded 4 Proxy to LiteLLM forward upstream call proxy LiteLLM proxy → upstream LLM usage metered (tokens, EUR) Usage ledger writes tokens · cost (EUR) response JSON (sync) { "choices": [ … ], "usage": {…} } SSE stream stream: true data: { "delta": "…" } data: [DONE] Every request passes all four gates before a token leaves the gateway; usage is metered on the return path.
Request-Fluss: Auth- und Governance-Gates vor dem Proxy, mit Usage-Metering nach der Antwort.

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

type

Bedeutung

400

invalid_request_error

Body ungültig (fehlendes model/messages, leeres messages-Array).

401

authentication_error

Bearer-Token fehlt, Key unbekannt oder widerrufen.

402

insufficient_quota

Monats-Budget der Firma erreicht.

403

permission_error

Scope chat:write fehlt oder Nicht-EU-Modell nicht freigeschaltet.

404

not_found_error

Modell-Slug unbekannt, inaktiv oder workspace-deaktiviert.

5xx

api_error

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_tokens

Python — 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:
        raise

Verwandte Endpunkte

Dieselbe Authentifizierung, Governance und dasselbe Metering gelten für:

Endpunkt

Zweck

GET /api/v1/models

OpenAI-kompatible Liste der für deine Firma erlaubten Chat- und Embedding-Modelle ({ object: "list", data: [{ id, object, created, owned_by }] }). Kein Scope erforderlich (nur gültiger Key).

POST /api/v1/embeddings

OpenAI-kompatible Embeddings (model + input). Benötigt Scope chat:write.

POST /api/v1/assistants/{id}/run

Führt einen konfigurierten Kasimir-Assistenten per API aus.

curl https://kasimir.ai/api/v1/models \
  -H "Authorization: Bearer $KASIMIR_API_KEY"