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:
X-RateLimit-Limit: Maximum requests per minuteX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when the window resets
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
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
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."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
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"
]
}
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
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"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
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"
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
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.