Kasimir Docs DEEN To the app →

API: Embeddings

OpenAI-compatible embeddings endpoint of the Kasimir Public API for 1024-dimensional vector embeddings.

The Kasimir Public API embeddings endpoint converts text into numeric vector embeddings that you can use for semantic search, clustering, classification, or your own RAG pipelines. The interface is wire-compatible with the OpenAI Embeddings API: you can use the official OpenAI Python SDK (or any OpenAI-compatible client) unchanged and simply point base_url and api_key at Kasimir. Internally the request is proxied through the GDPR-compliant LiteLLM proxy to the configured embedding model, with tenant governance (model entitlement, EU gate) and per-call usage metering.

Endpoint

Method

POST

URL

https://kasimir.ai/api/v1/embeddings

Base URL

https://kasimir.ai/api/v1

Content-Type

application/json

Auth

Authorization: Bearer <api-key>

Required scope

chat:write

ℹ️

OpenAI-compatible In any OpenAI client, set base_url = "https://kasimir.ai/api/v1" and api_key = "<your-kasimir-key>". The request and response shapes mirror OpenAI's POST /v1/embeddings.

Authentication

Every call is authenticated with a company API key passed in the Authorization: Bearer <key> header.

  • Keys are created by workspace owners or admins under Administration → Access (/administration/access).

  • The format is kasi_ followed by 32 characters (e.g. kasi_a3f9k2m7q4t6w8x1c5v9b2n4z6s8d0f2). The plaintext is shown only once at creation — afterwards Kasimir stores only a SHA-256 hash.

  • New keys default to the scopes chat:read and chat:write. Embeddings require chat:write.

  • Revoked keys (with revoked_at set) are rejected with 401.

⚠️

Never put the key in client code Treat the API key like a password. Use it server-side only and never commit it to a repository. If a key leaks, revoke it in /administration/access and create a new one.

Request

Headers

Header

Value

Required

Authorization

Bearer <api-key>

yes

Content-Type

application/json

yes

Body parameters

Parameter

Type

Required

Description

model

string

yes

The public model slug of an embedding model, e.g. self-hosted-bge-m3. Available slugs are returned by GET /api/v1/models.

input

string | string[]

yes

The text to embed. Either a single string or an array of strings for batch embedding.

💡

Extra fields are passed through The body is validated with passthrough semantics: additional OpenAI-compatible fields (e.g. encoding_format, dimensions, if the upstream model supports them) are forwarded verbatim to the LiteLLM proxy. Only model and input are mandatory and validated.

Response

The response follows the OpenAI embeddings schema. The model field in the response carries the Kasimir slug (not the internal upstream model ID).

Field

Type

Description

object

string

Always "list".

data

array

List of embedding objects (see below).

model

string

The requested Kasimir model slug.

usage

object

Token usage: prompt_tokens, total_tokens.

Each element in data:

Field

Type

Description

object

string

Always "embedding".

index

number

Position in the input array.

embedding

number[]

The vector. For the default model, 1024 dimensions.

ℹ️

Vector dimension The configured embedding model self-hosted-bge-m3 (BGE-M3, EU-hosted) returns 1024-dimensional vectors. Kasimir's RAG pipeline is fixed at vector(1024); switching to a model with a different dimension requires a new schema migration.

Examples

curl — single text

curl https://kasimir.ai/api/v1/embeddings \
  -H "Authorization: Bearer kasi_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "self-hosted-bge-m3",
    "input": "The GDPR governs the handling of personal data."
  }'

curl — batch (multiple texts)

curl https://kasimir.ai/api/v1/embeddings \
  -H "Authorization: Bearer kasi_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "self-hosted-bge-m3",
    "input": [
      "First paragraph to embed.",
      "Second paragraph to embed."
    ]
  }'

OpenAI Python SDK

from openai import OpenAI

client = OpenAI(
    base_url="https://kasimir.ai/api/v1",
    api_key="kasi_YOUR_API_KEY",
)

resp = client.embeddings.create(
    model="self-hosted-bge-m3",
    input="The GDPR governs the handling of personal data.",
)

vector = resp.data[0].embedding
print(len(vector))   # 1024
print(resp.usage.prompt_tokens)

Batch with the Python SDK

texts = [
    "First paragraph to embed.",
    "Second paragraph to embed.",
]

resp = client.embeddings.create(model="self-hosted-bge-m3", input=texts)

for item in resp.data:
    print(item.index, len(item.embedding))

Example response

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [0.0123, -0.0456, 0.0789, "...1021 more values..."]
    }
  ],
  "model": "self-hosted-bge-m3",
  "usage": {
    "prompt_tokens": 12,
    "total_tokens": 12
  }
}
POST /api/v1/embeddings Request lifecycle: auth → gate → budget → proxy → model → response Client curl / OpenAI SDK POST /v1/embeddings Authorization: Bearer kasi_… { input, model } Kasimir API Gateway 1 Authenticate verify kasi_ key hash scope: chat:write 2 Resolve model slug → bge-m3 EU-hosting gate 3 Assert budget monthly spend cap tenant ledger lookup all checks pass → forward LiteLLM proxy / router one wire format BGE-M3 embedding model 1024-dim vec 200 OK → { data:[ embedding ] } api_usage ledger +1 row: tokens · cost · model write
Request path of an embeddings call: auth, model governance, and budget check before the LiteLLM proxy, then metering.

Listing models

To discover which slugs are entitled for your workspace, use the models endpoint. It returns both chat and embedding models (filtered by tenant entitlement and the EU gate):

curl https://kasimir.ai/api/v1/models \
  -H "Authorization: Bearer kasi_YOUR_API_KEY"
client.models.list()

Errors

Errors are returned in the OpenAI error format so that standard SDKs handle them normally:

{
  "error": {
    "message": "Missing scope: chat:write",
    "type": "permission_error",
    "code": null
  }
}

The HTTP status code determines the type field:

Status

error.type

Cause

400

invalid_request_error

Invalid body (missing model/input or wrong type).

401

authentication_error

No bearer token, invalid key, or revoked key.

402

insufficient_quota

Workspace monthly budget reached.

403

permission_error

Missing scope (chat:write) or a non-EU model that is not entitled.

404

not_found_error

Model slug unknown, inactive, or disabled for the workspace.

>= 500

api_error

Upstream / proxy error (e.g. 502 Upstream error: …).

⚠️

Budget limit (402) If the workspace has a monthly_budget_eur set and the sum of API and in-app spend for the current calendar month reaches it, every call responds with 402. An unset budget, or one at ≤ 0, means "unlimited".

Governance & billing

  • Model entitlement: The same rules apply as in the in-app model picker — workspace scope, active, purpose embedding, the disabled_model_slugs deny-list, and the EU/non-EU gate (allow_non_eu_models).

  • EU gate: Non-EU models (eu_hosted = false) are rejected with 403 unless the workspace has explicitly enabled them. The default embedding model is EU-hosted.

  • Metering: Every successful call is recorded in the usage ledger (api_usage) — with prompt_tokens from the upstream response and the EUR cost per the model's rates. Metering is best-effort and never blocks the response.

💡

GDPR / data residency The default embedding slug self-hosted-bge-m3 is marked EU-hosted. If data residency is critical for you, verify via GET /api/v1/models that your chosen model is EU-hosted before embedding personal data.