API: Authentication
How to create Kasimir API keys and authenticate requests to the OpenAI-compatible REST API using a Bearer token.
The Kasimir public API is OpenAI-compatible and served from the base URL https://kasimir.ai/api/v1. Every request is authenticated with a company-scoped API key sent in the Authorization header — there is no session, no cookies, and no OAuth. A key always represents exactly one organization (tenant), and all usage (tokens, cost) is metered against that organization's monthly budget. Because the wire formats match OpenAI's, you can use the official OpenAI SDK unchanged — you only set base_url and api_key.
Overview
Property | Value |
|---|---|
Base URL |
|
Auth scheme |
|
Key format |
|
Scope | per organization (tenant) |
Compatibility | OpenAI Chat Completions, Embeddings, Models |
The API key is tenant-bound, not user-bound. Every request runs in the context of the organization the key was created for — using that org's enabled models, its model governance (EU gate, disabled models), and its monthly budget.
Creating an API key
API keys are managed exclusively in the web UI under Administration → Access (/administration/access). Only members with the owner or admin role may create, list, or revoke keys.
Open
/administration/access.Give the key a descriptive name (e.g.
ci-pipelineorcrm-integration).Create the key.
Copy the full key immediately — it is shown in plaintext exactly once.
The plaintext key is returned only once, at creation time. Kasimir stores only a SHA-256 hash of the secret — there is no way to re-display a lost key. If you lose it, revoke it and create a new one.
Key format
Each key has the form kasi_<32 chars>. The 32 characters are drawn from a 32-symbol base32-style alphabet (a–z, 2–7), giving 160 bits of entropy. The kasi_ prefix makes keys recognizable in logs. After creation, the management UI shows only the prefix (the first 9 characters, e.g. kasi_abx7) for identification.
Scopes
Scopes can be specified at creation; if omitted, the key receives the default scopes chat:read and chat:write.
Scope | Meaning | Required for |
|---|---|---|
| Read access (model list) | – |
| Run inference |
|
The runtime endpoints (chat, embeddings, assistant run) all require the chat:write scope. GET /models requires only a valid key (no specific scope). In practice almost every integration needs chat:write.
Authenticating a request
Send the key as a Bearer token in the Authorization header. The exact pattern Bearer <key> is expected (the word "Bearer" is case-insensitive).
curl https://kasimir.ai/api/v1/chat/completions \
-H "Authorization: Bearer kasi_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "chat1",
"messages": [
{ "role": "user", "content": "Say hello in German." }
]
}'Quick connectivity check against the models endpoint (needs only a valid key):
curl https://kasimir.ai/api/v1/models \
-H "Authorization: Bearer kasi_YOUR_KEY"Using the OpenAI Python SDK
Because the API is OpenAI-compatible, you only change base_url and api_key:
from openai import OpenAI
client = OpenAI(
api_key="kasi_YOUR_KEY",
base_url="https://kasimir.ai/api/v1",
)
# List available models
for m in client.models.list().data:
print(m.id)
# Chat completion
resp = client.chat.completions.create(
model="chat1",
messages=[{"role": "user", "content": "Say hello in German."}],
)
print(resp.choices[0].message.content)Provide the key via the OPENAI_API_KEY and OPENAI_BASE_URL environment variables and the SDK configures itself with no code change. Never hard-code keys in source or commit them to a repository.
Error format
Authentication and other errors are returned in the OpenAI error shape, so off-the-shelf SDKs surface them normally:
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": null
}
}Auth- and budget-related status codes
Status |
| Cause |
|---|---|---|
|
| No bearer token, invalid key, or revoked key |
|
| Organization's monthly budget reached |
|
| Missing scope (e.g. |
|
| Model unknown/disabled, or assistant not found |
|
| Invalid request body |
|
| Internal error or upstream problem |
Specific 401 messages by cause: Missing bearer token, Invalid API key, API key revoked. A missing scope returns 403 with Missing scope: chat:write.
For streamed chat ("stream": true), errors that occur before the stream starts (e.g. auth, budget) are delivered as a normal JSON error. If an error occurs once the SSE stream is already flowing, it can no longer be reshaped into the JSON format — the stream simply aborts.
Managing and revoking keys
In /administration/access, owners/admins see all the organization's keys with name, prefix, scopes, creation date, and last_used_at (updated best-effort on each authenticated request). Revoking sets revoked_at — revoked keys are immediately rejected with 401 API key revoked. Revocation is permanent; there is no reactivation.
Use a separate named key per integration/environment (e.g. prod-backend, staging, analytics-job). That way you can revoke a compromised or retired key in isolation without disrupting other integrations. Names must be unique per organization.
Security notes
Treat API keys like passwords: never commit them, never ship them to clients/browsers, never log them.
Keys do not expire — rotate them regularly via revoke + recreate.
All API usage counts toward the organization's monthly budget alongside in-app chat usage.
Model governance applies identically to the app: disabled models and non-EU models (without the org's opt-in) are blocked over the API too.