MENU navbar-image

Introduction

OpenAI-compatible API gateway for AI services. Use standard OpenAI SDKs with your kai API key.

Overview

kai provides an OpenAI-compatible API for AI services. You can use standard OpenAI SDKs by simply changing the base URL to your kai instance.

Authentication

All API endpoints require Bearer token authentication. Include your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Rate Limiting

All endpoints are rate-limited per API token. Check the X-RateLimit-* headers in every response:

When rate limited, you'll receive a 429 response with a Retry-After header.

Error Responses

All errors follow the OpenAI error format:

{
    "error": {
        "message": "Human-readable description",
        "type": "error_type",
        "code": "error_code",
        "param": "parameter_name"
    }
}
HTTP Status Type Description
400 invalid_request_error Invalid request format or parameters
401 authentication_error Invalid or missing API key
403 permission_error Token inactive, expired, or subscription inactive
429 rate_limit_error Rate limit exceeded
500 server_error Internal server error
503 server_error Service temporarily unavailable

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_API_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Contact office@kaino.io to obtain an API key.

Chat

Create a chat completion.

requires authentication

Generates a model response for the given conversation. Follows the OpenAI chat completions format. Token usage is included in successful responses and counted toward your billing period.

Streaming is not currently supported — set stream to false or omit it.

Example request:
curl --request POST \
    "https://wmp.kai.kaino.io/api/v1/chat/completions" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "X-Units-Remaining: 199" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"messages\": [
        {
            \"role\": \"system\",
            \"content\": \"You are a helpful assistant.\"
        },
        {
            \"role\": \"user\",
            \"content\": \"Hello!\"
        }
    ],
    \"model\": \"mistral-large-latest\",
    \"temperature\": 0.7,
    \"max_tokens\": 1024,
    \"top_p\": 1,
    \"stream\": false,
    \"n\": 1,
    \"presence_penalty\": 0,
    \"frequency_penalty\": 0
}"
const url = new URL(
    "https://wmp.kai.kaino.io/api/v1/chat/completions"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "X-Units-Remaining": "199",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": "Hello!"
        }
    ],
    "model": "mistral-large-latest",
    "temperature": 0.7,
    "max_tokens": 1024,
    "top_p": 1,
    "stream": false,
    "n": 1,
    "presence_penalty": 0,
    "frequency_penalty": 0
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'https://wmp.kai.kaino.io/api/v1/chat/completions'
payload = {
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": "Hello!"
        }
    ],
    "model": "mistral-large-latest",
    "temperature": 0.7,
    "max_tokens": 1024,
    "top_p": 1,
    "stream": false,
    "n": 1,
    "presence_penalty": 0,
    "frequency_penalty": 0
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'X-Units-Remaining': '199',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://wmp.kai.kaino.io/api/v1/chat/completions';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'X-Units-Remaining' => '199',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'messages' => [
                [
                    'role' => 'system',
                    'content' => 'You are a helpful assistant.',
                ],
                [
                    'role' => 'user',
                    'content' => 'Hello!',
                ],
            ],
            'model' => 'mistral-large-latest',
            'temperature' => 0.7,
            'max_tokens' => 1024,
            'top_p' => 1.0,
            'stream' => false,
            'n' => 1,
            'presence_penalty' => 0.0,
            'frequency_penalty' => 0.0,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Successful completion):


{
    "id": "chatcmpl-kai-abc123",
    "object": "chat.completion",
    "model": "mistral-large-latest",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "Hello! How can I help you today?"
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 25,
        "completion_tokens": 12,
        "total_tokens": 37
    }
}
 

Request      

POST api/v1/chat/completions

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

X-Units-Remaining        

Example: 199

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

messages   object[]     

The messages to generate chat completions for. validation.min.

role   string     

The role of the message author. Must be system, user, or assistant. Example: user

Must be one of:
  • system
  • user
  • assistant
content   string     

The content of the message. validation.min. Example: Hello!

model   string  optional    

The model to use for completion. Use GET /v1/models to list available models. If omitted, the default model for your plan is used. Example: mistral-large-latest

temperature   number  optional    

Sampling temperature between 0 and 2. Higher values make output more random. validation.min validation.max. Example: 0.7

max_tokens   integer  optional    

Maximum number of tokens to generate. Range: 1-32768. validation.min validation.max. Example: 1024

top_p   number  optional    

Nucleus sampling probability. Range: 0-1. validation.min validation.max. Example: 1

stream   boolean  optional    

Streaming is not currently supported. Must be false or omitted. Example: false

n   integer  optional    

Number of completions. Accepted for compatibility but always returns 1. validation.min validation.max. Example: 1

stop   string  optional    

Stop sequences. Accepted for compatibility but not supported.

presence_penalty   number  optional    

Presence penalty (-2 to 2). Accepted for compatibility but not supported. validation.min validation.max. Example: 0

frequency_penalty   number  optional    

Frequency penalty (-2 to 2). Accepted for compatibility but not supported. validation.min validation.max. Example: 0

Audio

Transcribe audio or video.

requires authentication

Transcribes speech from an audio or video file. For video uploads, the audio track is automatically extracted before transcription. The file must contain at least one audio stream.

Compatible with the OpenAI Whisper API format.

Example request:
curl --request POST \
    "https://wmp.kai.kaino.io/api/v1/audio/transcriptions" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "X-Units-Remaining: 199" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "model=whisper-1"\
    --form "language=de"\
    --form "prompt=This is a medical consultation."\
    --form "response_format=json"\
    --form "temperature=0"\
    --form "file=@/tmp/phpkq69ehco1qahfggiCmL" 
const url = new URL(
    "https://wmp.kai.kaino.io/api/v1/audio/transcriptions"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "X-Units-Remaining": "199",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('model', 'whisper-1');
body.append('language', 'de');
body.append('prompt', 'This is a medical consultation.');
body.append('response_format', 'json');
body.append('temperature', '0');
body.append('file', document.querySelector('input[name="file"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());
import requests
import json

url = 'https://wmp.kai.kaino.io/api/v1/audio/transcriptions'
files = {
  'model': (None, 'whisper-1'),
  'language': (None, 'de'),
  'prompt': (None, 'This is a medical consultation.'),
  'response_format': (None, 'json'),
  'temperature': (None, '0'),
  'file': open('/tmp/phpkq69ehco1qahfggiCmL', 'rb')}
payload = {
    "model": "whisper-1",
    "language": "de",
    "prompt": "This is a medical consultation.",
    "response_format": "json",
    "temperature": 0
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'X-Units-Remaining': '199',
  'Content-Type': 'multipart/form-data',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, files=files)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://wmp.kai.kaino.io/api/v1/audio/transcriptions';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'X-Units-Remaining' => '199',
            'Content-Type' => 'multipart/form-data',
            'Accept' => 'application/json',
        ],
        'multipart' => [
            [
                'name' => 'model',
                'contents' => 'whisper-1'
            ],
            [
                'name' => 'language',
                'contents' => 'de'
            ],
            [
                'name' => 'prompt',
                'contents' => 'This is a medical consultation.'
            ],
            [
                'name' => 'response_format',
                'contents' => 'json'
            ],
            [
                'name' => 'temperature',
                'contents' => '0'
            ],
            [
                'name' => 'file',
                'contents' => fopen('/tmp/phpkq69ehco1qahfggiCmL', 'r')
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Successful transcription):


{
    "text": "Der Patient berichtet über anhaltende Kopfschmerzen seit zwei Wochen."
}
 

Request      

POST api/v1/audio/transcriptions

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

X-Units-Remaining        

Example: 199

Content-Type        

Example: multipart/form-data

Accept        

Example: application/json

Body Parameters

file   file     

The audio or video file to transcribe. Max 25MB. Supported formats: mp3, m4a, wav, webm, ogg, flac, aac (audio), mp4, webm, mov, avi, mkv (video with audio track). Must be a file. validation.max. Example: /tmp/phpkq69ehco1qahfggiCmL

model   string     

The transcription model to use. Use GET /v1/models to list available models for your plan. Example: whisper-1

Must be one of:
  • whisper-1
language   string  optional    

The language of the audio in ISO-639-1 format (e.g., de, en). Optional. validation.size. Example: de

prompt   string  optional    

Optional text to guide the model's style. Max 1000 characters. validation.max. Example: This is a medical consultation.

response_format   string  optional    

The format of the transcript output: json, text, srt, verbose_json, or vtt. Example: json

Must be one of:
  • json
  • text
  • srt
  • verbose_json
  • vtt
temperature   number  optional    

Sampling temperature between 0 and 1. Lower is more deterministic. validation.min validation.max. Example: 0

Documents

Anonymize documents by detecting and replacing PII with placeholders.

requires authentication

Upload 1 file (PDF, DOCX, images, plain text). The API extracts text (with OCR fallback for scanned documents), detects personally identifiable information, and replaces it with numbered placeholders like [[NAME_1]], [[EMAIL_2]].

Returns the sanitized text, a sanitized filename, and a mapping of placeholders to their original values.

Requires the documents_anonymize permission on your API token's product.

Example request:
curl --request POST \
    "https://wmp.kai.kaino.io/api/v1/documents/anonymize" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "X-Units-Remaining: 199" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "language=de"\
    --form "pii_types[]=name"\
    --form "files[]=@/tmp/phpm7etuh9h4tcmdiTb8pp" 
const url = new URL(
    "https://wmp.kai.kaino.io/api/v1/documents/anonymize"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "X-Units-Remaining": "199",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('language', 'de');
body.append('pii_types[]', 'name');
body.append('files[]', document.querySelector('input[name="files[]"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());
import requests
import json

url = 'https://wmp.kai.kaino.io/api/v1/documents/anonymize'
files = {
  'language': (None, 'de'),
  'pii_types[]': (None, 'name'),
  'files[]': open('/tmp/phpm7etuh9h4tcmdiTb8pp', 'rb')}
payload = {
    "language": "de",
    "pii_types": [
        "name"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'X-Units-Remaining': '199',
  'Content-Type': 'multipart/form-data',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, files=files)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://wmp.kai.kaino.io/api/v1/documents/anonymize';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'X-Units-Remaining' => '199',
            'Content-Type' => 'multipart/form-data',
            'Accept' => 'application/json',
        ],
        'multipart' => [
            [
                'name' => 'language',
                'contents' => 'de'
            ],
            [
                'name' => 'pii_types[]',
                'contents' => 'name'
            ],
            [
                'name' => 'files[]',
                'contents' => fopen('/tmp/phpm7etuh9h4tcmdiTb8pp', 'r')
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Successful anonymization):


{
    "object": "list",
    "data": [
        {
            "original_filename": "patient_report.pdf",
            "sanitized_filename": "patient_report.pdf",
            "sanitized_text": "Patient: [[NAME_1]]\nDiagnose: [[MEDICAL_1]]",
            "placeholders": {
                "[[NAME_1]]": "Max Mustermann",
                "[[MEDICAL_1]]": "Diabetes Typ 2"
            },
            "metadata": {
                "extraction_method": "pdf_parser",
                "used_ocr": false,
                "page_count": 2,
                "pii_count": 2,
                "strategy": "ai",
                "pii_types_requested": [
                    "name",
                    "medical"
                ]
            }
        }
    ]
}
 

Request      

POST api/v1/documents/anonymize

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

X-Units-Remaining        

Example: 199

Content-Type        

Example: multipart/form-data

Accept        

Example: application/json

Body Parameters

files   file[]     

A document file to anonymize. Must be a file. validation.max.

language   string  optional    

Document language for PII detection: de (German) or en (English). Defaults to de. validation.min validation.max. Example: de

pii_types   string[]     

A PII type to detect.

Must be one of:
  • name
  • email
  • phone
  • dob
  • address
  • insurance
  • iban
  • company
  • medical
  • credit_card
  • passport
  • vehicle
  • ip_address
  • url
  • username
  • vat_number
  • company_register
  • healthcare_number
  • tax_id
  • age
  • nationality
  • gender
  • religion
  • occupation

Models

List available models.

requires authentication

Returns models available for your API token. Use the model id values when calling chat or audio endpoints.

Example request:
curl --request GET \
    --get "https://wmp.kai.kaino.io/api/v1/models" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://wmp.kai.kaino.io/api/v1/models"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://wmp.kai.kaino.io/api/v1/models'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://wmp.kai.kaino.io/api/v1/models';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Available models):


{
    "object": "list",
    "data": [
        {
            "id": "mistral-large-latest",
            "object": "model",
            "created": 1700000000,
            "owned_by": "kai"
        },
        {
            "id": "mistral-small-latest",
            "object": "model",
            "created": 1700000000,
            "owned_by": "kai"
        },
        {
            "id": "voxtral-mini-latest",
            "object": "model",
            "created": 1700000000,
            "owned_by": "kai"
        }
    ]
}
 

Request      

GET api/v1/models

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Usage

Get current billing period usage statistics.

requires authentication

Returns token status, product info, and usage counts for the current month. The status field indicates whether the token is currently usable (active) or not (inactive).

Example request:
curl --request GET \
    --get "https://wmp.kai.kaino.io/api/v1/usage" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "https://wmp.kai.kaino.io/api/v1/usage"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'https://wmp.kai.kaino.io/api/v1/usage'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()
$client = new \GuzzleHttp\Client();
$url = 'https://wmp.kai.kaino.io/api/v1/usage';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {YOUR_API_KEY}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));

Example response (200, Usage statistics):


{
    "status": "active",
    "is_trial": false,
    "trial_ends_at": null,
    "period": "2025-01",
    "product": "aegis-pro",
    "product_label": "Aegis PRO",
    "usage_label": "API Requests",
    "total_requests": 42,
    "total_ok": 40,
    "total_errors": 2,
    "total_tokens_in": 12500,
    "total_tokens_out": 3200,
    "rate_limit_per_minute": 10,
    "max_concurrent_requests": 1,
    "monthly_usage_cap": 100,
    "usage_remaining": 60,
    "addons": [],
    "enabled_features": [],
    "enabled_endpoints": [
        "chat_completions",
        "audio_transcriptions",
        "documents_anonymize"
    ]
}
 

Request      

GET api/v1/usage

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Response

Response Fields

rate_limit_per_minute   integer     

Maximum requests per minute for this token.

max_concurrent_requests   integer     

Maximum simultaneous POST requests allowed.

monthly_usage_cap   integer     

Maximum successful requests per month. Null if unlimited.

usage_remaining   integer     

Remaining requests in current month. Null if unlimited.