This is the single-file HTTP API contract for teams that integrate Kroov
into another application. The same document lives in the repository as
docs/API-INTEGRATION-GUIDE.md. The other pages in this API section are the
same contract split for browsing.
API Integration Guide
Kroov Platform
Document Version: 2.0
Date: August 2026
Status: Production-Ready
Classification: Public - Developer Documentation
Document Purpose
This guide provides comprehensive documentation for developers integrating applications with the Kroov Platform. It covers the full HTTP API surface as of August 2026, including:
- Authentication methods (API key, JWT, OAuth, delegation)
- Feature flags and deployment capability discovery
- AI request, chat, multimodal, streaming, and OpenAI-compatible endpoints
- Projects, prompts, providers, cost, and dashboard APIs
- Internal Knowledge Bases (pgvector RAG) and document ingestion
- MCP control plane (servers, catalog, definitions, instances, runtimes, proxy)
- Configurable Agents, environments, presets, headless runs, and interactive sessions
- Autonomous scheduled tasks
- Event automations, Pipedream connections, approvals, and signed webhooks
- GitHub App integration, federation, and security endpoints
- Request/response formats, SSE/WebSocket streaming, errors, and best practices
Audience: Application developers, integration teams, third-party vendors, and platform operators (EMR and other clinical systems are optional integration examples)
Related deep-dive docs (architecture / ops — this guide remains the API contract):
| Topic | Document |
|---|---|
| Internal RAG / pgvector | docs/INTERNAL-RAG.md |
| Configurable agents & sessions | docs/CONFIGURABLE-AGENTS.md |
| Scheduled tasks | docs/AUTONOMOUS-SCHEDULED-TASKS.md |
| Automations walkthrough | docs/automations-demo.md |
| MCP on Kubernetes | docs/MCP-KUBERNETES.md |
| Native WhatsApp Business | docs/WHATSAPP-BUSINESS.md |
| Native Telegram | docs/TELEGRAM.md |
| Personal assistant | docs/PERSONAL-ASSISTANT.md |
Table of Contents
- Getting Started
- Authentication
- Feature Flags & Capability Discovery
- API Endpoints Reference
- 4.1 AI Query Endpoints
- 4.2 OpenAI-Compatible API (
/v1) - 4.3 Chat History
- 4.4 Projects, Members & Federation
- 4.5 Prompts
- 4.6 Providers
- 4.7 Knowledge Bases
- 4.8 MCP Platform
- 4.9 Agents & Environments
- 4.10 Agent Runs (headless Jobs)
- 4.11 Interactive Sessions
- 4.12 Scheduled Tasks
- 4.13 Automations, Connections & Approvals
- 4.14 GitHub App Integration
- 4.15 Cost, Dashboard & Logs
- 4.16 Security & Health
- Request & Response Formats
- Streaming API
- Error Handling
- Code Examples
- Best Practices
- Security Considerations
- Troubleshooting
- Appendices
1. Getting Started
1.1 Base URL
Production / staging (placeholder):
{baseUrl}/api
or
https://your-kroov-host/api
Local:
https://localhost:7003/api
WebApp (Vite): https://localhost:3007 — proxies /api → :7003.
Note: Many deployments are reachable only from a private network. Public Internet access is usually disabled unless federation or a public webhook base URL is intentionally configured.
OpenAI-compatible routes live under /v1 (not /api/v1):
{baseUrl}/v1/chat/completions
or https://your-kroov-host/v1/chat/completions.
Liveness probe (anonymous): GET /health → { "status": "healthy" }.
1.2 API Versioning
Current Version: v1 (implicit for /api/*; explicit OpenAI surface at /v1)
Future breaking changes may introduce /api/v2/. Until then, additive fields are preferred; clients should ignore unknown JSON properties.
1.3 Content Types
Request:
application/json— JSON bodies (property names are camelCase)multipart/form-data— file uploads (images, documents, audio, KB documents, session files)
Response:
application/json— standard responsestext/event-stream— Server-Sent Events (chat agent loop, agent runs, sessions)- WebSocket JSON frames — live realtime transcription
1.4 Auth at a glance
| Audience | Scheme | Header / mechanism |
|---|---|---|
| EMR / backend apps calling AI | API Key | x-api-key: <key> |
| OpenAI SDK clients | API Key as Bearer | Authorization: Bearer <api-key> on /v1/* |
| SPA / admin / agents / automations | JWT | Authorization: Bearer <jwt> |
| Federated MCP callers (e.g. Eva) | Delegation | X-AINexus-Delegation: <token> |
| Pipedream webhooks | HMAC | x-pd-signature on POST /api/integration-events/... |
| MCP runtime proxy (internal) | Controller token | X-Mcp-Controller-Token |
Important: Native AI endpoints under
/api/ai/*accept API Key authentication only (AuthenticationSchemes = "ApiKey"). JWT works for admin/SPA controllers, not for/api/ai/queryor/api/ai/chat.
1.5 Quick Start Checklist
- Obtain an API key (or JWT for admin surfaces) from a platform administrator
- Identify your project ID
- Call
GET /api/featuresto learn which optional capabilities this deployment exposes - Test in development first
- Prefer
providerId(specific configured instance) over bareprovidertype strings
First AI call (API key):
curl -X POST https://your-kroov-host/api/ai/query \
-H "x-api-key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Hello, this is a test query",
"projectId": 1
}'
Expected response:
{
"success": true,
"content": "Hello! How can I assist you today?",
"provider": "Azure",
"providerId": 12,
"executionDuration": "00:00:01.234",
"requestId": 12345,
"inputTokens": 10,
"outputTokens": 15
}
Local admin login → JWT (Development with Authentication__EnableLocalLogin=true):
curl -s -X POST https://localhost:7003/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}'
1.6 Interactive API Documentation
Swagger UI (Development environment only):
{baseUrl}/swagger
https://localhost:7003/swagger
Configure ApiKey (x-api-key) and/or Bearer JWT in the Authorize dialog.
2. Authentication
2.1 Authentication Methods
| Method | Typical use |
|---|---|
| API Key | Application integrations, EMR, OpenAI-compat clients |
| JWT Bearer | WebApp, admin CRUD, agents, sessions, automations |
| Google OAuth | Interactive SPA login (DefaultLoginMode=Google in many deploys) |
| Delegation token | External services acting for a federated user on MCP instance APIs |
| Local login | Dev / testing only (Authentication:EnableLocalLogin) |
Discover which login modes are enabled:
curl -s https://your-kroov-host/api/auth/options
{
"enableLocalLogin": false,
"enableGoogleLogin": true,
"googleOAuthConfigured": true,
"defaultLoginMode": "Google"
}
2.2 API Key Authentication
- An administrator creates a key via
POST /api/auth/apikey(or project rotate-key flows) - The key may be scoped to a project
- Clients send
x-api-key: <secret>on every request - On
/v1/*,Authorization: Bearer <api-key>is also accepted (rewritten to ApiKey)
POST /api/ai/query HTTP/1.1
Host: your-kroov-host
x-api-key: ainx_...
Content-Type: application/json
{ "prompt": "Your query here", "projectId": 1 }
Security:
- Store keys in a secrets manager / environment variables — never in source control
- Rotate periodically; use separate keys for dev and production
- Never put keys in URL query strings except for WebSocket clients that cannot set headers (prefer first-message
authwhen possible) - Never log raw keys
Create / list API keys (JWT required)
# Create — secret returned once
curl -X POST https://your-kroov-host/api/auth/apikey \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "name": "EMR Integration", "projectId": 1, "expiresAt": null }'
# List summaries (no secrets)
curl "https://your-kroov-host/api/auth/apikey?projectId=1" \
-H "Authorization: Bearer $JWT"
{
"key": "ainx_...",
"name": "EMR Integration",
"expiresAt": null
}
2.3 JWT Authentication
Obtain via local login (dev):
curl -X POST https://your-kroov-host/api/auth/login \
-H "Content-Type: application/json" \
-d '{ "username": "your-username", "password": "your-password" }'
Google OAuth: GET /api/auth/google (browser redirect).
Refresh / logout:
curl -X POST .../api/auth/refresh -H 'Content-Type: application/json' \
-d '{ "refreshToken": "..." }'
curl -X POST .../api/auth/logout -H 'Content-Type: application/json' \
-d '{ "refreshToken": "..." }'
Using JWT:
GET /api/project HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Typical lifetimes: access token ~60 minutes; refresh token ~7 days (deployment-configurable).
Admin policy (AdminOnly): JWT Admin role, or Google admin email allow-list. Many write endpoints require it.
2.4 Google OAuth
GET /api/auth/google— start Google OAuth (browser redirect)
SPA token hand-off (useful in headless / local testing): navigate to
/login?token=<JWT>&refreshToken=<REFRESH> after calling the login API.
2.5 Delegation tokens (federation)
External apps exchange verified service + user identity for a short-lived X-AINexus-Delegation token used with MCP instance APIs and chat:
curl -X POST https://your-kroov-host/api/delegations/exchange \
-H "x-api-key: PROJECT_API_KEY" \
-H "X-AINexus-Service-Token: <gcp-sa-jwt>" \
-H "X-AINexus-User-Token: <google-user-jwt>" \
-H "Content-Type: application/json" \
-d '{ "phoneProof": "<optional-eva-phone-jwt>", "scopes": ["mcp:pair", "mcp:invoke", "mcp:manage"] }'
{ "token": "...", "tokenType": "Kroov-Delegation", "expiresIn": 300 }
See §4.4 Federation and §4.8 MCP.
2.6 Global authorization notes
- The API applies a fallback
RequireAuthenticatedUserpolicy: controllers must explicitly[AllowAnonymous]for public routes (auth options, features, webhooks, health, CSP report, MCP proxy with controller token, etc.). - JSON uses camelCase everywhere.
- Multipart field names match property names (
providerId,projectId,noLog, …).
3. Feature Flags & Capability Discovery
Optional product surfaces are gated by configuration. Always call this before assuming Agents / Sessions / Automations / hosted MCP are available.
GET /api/features — AllowAnonymous
curl -s https://localhost:7003/api/features
{
"hostedMcpRuntimes": true,
"kubernetesAgents": true,
"agentSessions": true,
"scheduledTasks": true,
"automations": true,
"isDevelopment": true,
"pipedreamConfigured": false
}
| Response field | True when |
|---|---|
hostedMcpRuntimes | Kubernetes:Enabled |
kubernetesAgents | Agents:Enabled and Kubernetes:Enabled |
agentSessions | AgentSessions:Enabled and Kubernetes:Enabled |
scheduledTasks | ScheduledTasks:Enabled and sessions (above) |
automations | Automations:Enabled only — does not require Kubernetes |
isDevelopment | Hosting environment is Development |
pipedreamConfigured | Pipedream OAuth (ClientId+ClientSecret+ProjectId) or legacy ApiKey is set |
HTTP 503 is returned by gated controllers when a feature is off (automations, scheduled tasks create/update, hosted MCP attribute, internal KB when disabled / non-PostgreSQL, agent runs when Agents disabled, etc.).
| Capability | Needs K8s? | Config keys |
|---|---|---|
| Hosted MCP instances / runtime proxy | Yes | Kubernetes:Enabled, controller token |
Headless agent Jobs (POST /api/agents/{id}/runs) | Yes | Agents:Enabled |
| Interactive sessions | Yes | AgentSessions:Enabled |
| Scheduled tasks | Yes (via sessions) | ScheduledTasks:Enabled |
| Event automations | No (in-process Service runtime) | Automations:Enabled, Automations:PublicWebhookBaseUrl |
| Internal Knowledge Bases | PostgreSQL + pgvector + object storage | KnowledgeBase:Internal:Enabled |
4. API Endpoints Reference
4.1 AI Query Endpoints
Controller: AIController — route prefix api/AI
Authentication: API Key only (x-api-key)
Provider selection — provider vs providerId
| Input | Type | Description |
|---|---|---|
provider | string (optional) | Logical provider type: Azure, Bedrock, Ollama, Gemini, … The platform resolves an active configuration for that type. |
providerId | integer (optional) | Specific provider instance (database row). When present, it takes precedence over provider. The instance must be active and must support the capability required (text, image, document, speech, agent tools, embeddings, realtime). |
JSON and multipart both use camelCase: providerId, not provider_id.
Where providerId is accepted: POST /api/ai/query, /queryImage, /queryDocument, /queryAudio, /chat, and the realtime WebSocket start message.
No-Log Requests
By default every request is fully logged. A request may opt out of logging its prompt and response by setting noLog: true (JSON) or noLog=true (multipart). This is a two-level control:
- Project permission (admin): Allow no-log requests must be enabled on the project.
- Per-request flag: caller sets
noLog: true.
When both are met, the LogEntry row is still created (system prompt + metrics retained) but RequestPrompt / PromptResponse are stored as null.
For OpenAI-compat: { "extension": { "noLog": true } }.
POST /api/ai/query
Text completion / one-shot query.
{
"prompt": "What is the recommended workflow for onboarding?",
"projectId": 1,
"promptId": 5,
"provider": "Azure",
"providerId": 12,
"stream": false,
"externalId": "EMR-12345",
"externalUser": "doctor-smith",
"noLog": false,
"parameters": { "temperature": 0.7, "maxTokens": 500 },
"messageHistory": [
{ "role": "user", "content": "Context from a prior turn" },
{ "role": "assistant", "content": "…" }
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | ✅ | Text query |
projectId | integer | ❌ | Project (often implied by API key) |
promptId | integer | ❌ | Prompt template |
provider / providerId | string / int | ❌ | Routing (see above) |
stream | boolean | ❌ | SSE streaming (default false) |
externalId / externalUser | string | ❌ | Caller tracking ids |
noLog | boolean | ❌ | See No-Log Requests |
parameters | object | ❌ | temperature, maxTokens, … |
messageHistory | array | ❌ | Prior { role, content } turns |
Success (non-stream):
{
"success": true,
"content": "A typical onboarding workflow includes…",
"errorMessage": null,
"provider": "Azure",
"providerId": 12,
"executionDuration": "00:00:02.345",
"requestId": 12345,
"inputTokens": 25,
"outputTokens": 150
}
Status codes: 200, 400, 401, 403, 500, 502 (provider failure).
curl -X POST https://your-kroov-host/api/ai/query \
-H "x-api-key: your-api-key" \
-H "Content-Type: application/json" \
-d '{ "prompt": "Explain the escalation policy", "projectId": 1, "providerId": 12 }'
POST /api/ai/queryImage
Vision analysis. multipart/form-data.
| Field | Type | Required | Description |
|---|---|---|---|
file | file | ✅ | PNG, JPEG, GIF, WebP, BMP (max ~20 MB) |
prompt | string | ✅ | Question about the image |
projectId, promptId, provider, providerId | ❌ | Routing / templates | |
stream, externalId, externalUser, noLog | ❌ | Same semantics as /query |
curl -X POST https://your-kroov-host/api/ai/queryImage \
-H "x-api-key: your-api-key" \
-F "file=@xray.png" \
-F "prompt=Describe what you see" \
-F "projectId=1" \
-F "providerId=12"
POST /api/ai/queryDocument
Document Q&A. multipart/form-data. Formats: PDF, DOCX, TXT, CSV, XLSX, XLS (max ~50 MB).
| Field | Type | Required | Description |
|---|---|---|---|
file | file | ✅ | Document |
prompt | string | ✅ | Question |
providerId | integer | ❌ | Supported — specific instance |
| Other fields | ❌ | Same pattern as queryImage |
curl -X POST https://your-kroov-host/api/ai/queryDocument \
-H "x-api-key: your-api-key" \
-F "file=@report.pdf" \
-F "prompt=Summarize key points" \
-F "projectId=1" \
-F "providerId=12"
POST /api/ai/queryAudio
Batch transcription (+ optional prompt formatting). multipart/form-data. Formats: MP3, WAV, WebM, OGG, M4A, MP4, FLAC, AAC (max ~100 MB).
| Field | Type | Required | Description |
|---|---|---|---|
file | file | ✅ | Audio |
language | string | ❌ | Omit / "auto" = detect; or fr / en / he |
providerId | integer | ❌ | Instance with speech capability |
enableSpeakerDiarization | boolean | ❌ | Person 1 / Person 2 labels |
usePromptForFormatting | boolean | ❌ | Run formatting prompt after STT |
promptId / transcriptionPromptId / formattingPromptId | int | ❌ | Templates |
projectId, stream, externalId, externalUser, noLog | ❌ | Standard |
Response includes audioDuration (seconds) when available.
WebSocket — Live realtime transcription
Endpoint: wss://{host}/api/ai/realtime/transcribe
Auth: x-api-key query, handshake header, or first message { "type":"auth", "apiKey":"..." }.
Audio: PCM16 mono 24 kHz, ~100 ms base64 chunks.
Client type | Fields | Purpose |
|---|---|---|
auth | apiKey | If not provided via query/header |
start | providerId?, projectId?, language?, externalId?, externalUser? | Open Azure Realtime session |
audio | data (base64 PCM16) | Append chunk |
stop | — | End |
Server type | Meaning |
|---|---|
session_ready | Safe to send audio |
partial / final | Transcript deltas |
speech_started / speech_stopped | VAD |
error / done | Failure / close (logged as audio-realtime) |
Provider config: type AzureRealtime (or Azure with realtime capability), supportsRealtimeAudio, realtimeDeployment (e.g. gpt-realtime).
Batch queryAudio | Live WebSocket | |
|---|---|---|
| Input | File | PCM16 stream |
| Latency | End of file | Partial + final while speaking |
| Capability | SupportsAudio | SupportsRealtimeAudio |
POST /api/ai/chat
Stateful conversational chat with optional MCP agent loop, knowledge-base grounding, attachments, and agent-definition grants.
{
"chatId": null,
"messageUser": "Draft a reply to this customer message",
"messageServer": null,
"projectId": 1,
"promptId": 5,
"providerId": 12,
"stream": true,
"endSession": false,
"externalId": "EMR-12345",
"externalUser": "doctor-smith",
"noLog": false,
"parameters": { "temperature": 0.7, "maxTokens": 500 },
"knowledgeBaseIds": [3, 7],
"agentDefinitionId": 1,
"attachments": [
{
"base64Data": "<base64>",
"contentType": "application/pdf",
"fileName": "note.pdf"
}
],
"delegation": {
"enableRemoteTools": true,
"mcpServerIds": [12],
"mcpInstanceId": null,
"mcpAccountNames": { "12": "default" },
"maxToolRounds": 10,
"maxToolCalls": 10,
"credential": null
}
}
| Parameter | Type | Required | Description |
|---|---|---|---|
messageUser | string | ✅ | User message |
messageServer | string | ❌ | Extra server instructions |
chatId | GUID string | ❌ | Null = new session |
projectId / promptId / provider / providerId | ❌ | Routing | |
stream | boolean | ❌ | SSE (recommended for MCP tools) |
endSession | boolean | ❌ | Close session |
knowledgeBaseIds | int[] | ❌ | Internal KB grounding for a normal text provider (not a KnowledgeBase provider type) |
agentDefinitionId | int | ❌ | Inherit agent MCP allow-list + tool grants; materializes a chat-scoped invocation |
attachments | array | ❌ | Multimodal base64 attachments (audio/image/document) converted server-side |
delegation | object | ❌ | MCP agent loop configuration |
delegation fields:
| Field | Type | Description |
|---|---|---|
enableRemoteTools | boolean | Enable MCP / tool agent loop |
credential | string | Inline JWT / API key / PAT when required |
mcpServerId | int | Single server when project has several |
mcpServerIds | int[] | Multi-MCP; null = unspecified, [] = no MCP (grants only), non-empty = exact set |
mcpInstanceId / mcpInstanceIds | guid / map | Managed worker instance(s) |
mcpAccountNames | map | Per-server vault account name |
maxToolRounds / maxToolCalls | int | Loop limits (default 10) |
internalApiBaseUrl | string | Override for InternalAPI-style MCPs |
contextOverrides | object | Sandbox overrides |
Flow: first message with chatId: null → response includes chatId → subsequent turns reuse it → endSession: true to close.
SSE events (when stream: true and tools enabled): content, toolCalls, status, tokens, error, [DONE].
POST /api/ai/vote/{requestId}
POST /api/ai/vote/chat/{chatId}/{messageIndex}
{ "isThumbsUp": true, "comment": "Accurate and concise" }
Field name is
isThumbsUp(notvote).
GET /api/ai/logs
Project logs visible to the API key (filters: date range, prompt text, externalId, …).
GET /api/ai/assistants?providerId=
List Azure Assistants for a provider.
GET /api/ai/download-blob?blobUrl= / GET /api/ai/view-blob?blobUrl=
Download or inline-view a knowledge-base / storage blob URL previously returned by the platform.
4.2 OpenAI-Compatible API (/v1)
Controller: OpenAiCompatController — route prefix v1
Authentication: API Key via Authorization: Bearer <api-key> or x-api-key
| Method | Path | Purpose |
|---|---|---|
GET | /v1/models | List models / provider aliases |
GET | /v1/models/{id} | Model detail |
POST | /v1/chat/completions | Chat completions (tools / MCP supported via platform translation) |
POST | /v1/audio/transcriptions | Multipart transcription |
POST | /v1/embeddings | Embeddings (same service as internal RAG) |
Kroov extension on chat completions:
{
"model": "gpt-4o",
"messages": [{ "role": "user", "content": "Hello" }],
"extension": { "noLog": true }
}
POST /v1/embeddings accepts a string or array of strings and returns float vectors (currently 1536-d for internal RAG).
curl https://your-kroov-host/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"messages": [{"role":"user","content":"Summarize the product guidelines"}]
}'
4.3 Chat History
User-scoped — ChatController (api/Chat) — JWT or API Key
| Method | Path | Purpose |
|---|---|---|
GET | /api/chat/sessions?externalUser=&externalId=&includeInactive= | List sessions for caller identity |
GET | /api/chat/conversation/{chatId}?externalUser=&externalId= | Full Q/A transcript |
Admin — ChatAdminController (api/ChatAdmin) — AdminOnly
| Method | Path | Purpose |
|---|---|---|
GET | /api/chatadmin/sessions?projectId=&externalUser=&externalId= | Cross-user listing |
GET | /api/chatadmin/conversation/{chatId} | Ops transcript |
4.4 Projects, Members & Federation
Projects — ProjectController (api/Project) — JWT
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/project?includeSpent= | Auth | List projects |
GET | /api/project/{id} | Auth | Detail |
POST | /api/project | Admin | Create |
PUT | /api/project/{id} | Admin | Update |
DELETE | /api/project/{id} | Admin | Delete |
POST | /api/project/{id}/rotate-key | Admin | Rotate project API key |
GET | /api/project/{id}/members | Project access | Members |
POST | /api/project/{id}/members | Admin/Owner | { "username", "role?" } |
DELETE | /api/project/{id}/members/{userId} | Admin/Owner | Remove |
POST | /api/project/spent | Auth | Body int[] → spent by project |
{
"name": "Operations",
"allowedAdGroups": null,
"allowedAdUsers": null,
"budget": 1000,
"allowNoLog": false
}
4.4.4 Federation — MCP entitlements
Controller: ProjectFederationController — api/projects/{projectId}/federation — AdminOnly
| Method | Path | Purpose |
|---|---|---|
GET | .../external-principals | List external principals |
POST | .../identity-providers | Register IdP (google-user, eva-phone, …) |
POST | .../service-identities | Register service identity (e.g. Cloud Run SA) |
POST | .../mcp-entitlements | Grant MCP entitlement |
GET | .../mcp-entitlements | List |
DELETE | .../mcp-entitlements/{id} | Revoke |
GET | .../internal-users | Internal users |
Entitlement body example: { "mcpServerId": 5, "userId": null, "externalPrincipalId": "…", "maxInstances": 1 }.
Delegation exchange: POST /api/delegations/exchange — see §2.5.
4.5 Prompts
Controller: PromptController (api/Prompt) — JWT; mutations Admin
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/prompt/project/{projectId} | Auth | List |
GET | /api/prompt/project/{projectId}/active | Auth | Active prompt |
GET | /api/prompt/{id} | Auth | Get |
POST | /api/prompt | Admin | Create |
PUT | /api/prompt/{id} | Admin | Update |
POST | /api/prompt/{id}/activate | Admin | Activate |
DELETE | /api/prompt/{id} | Admin | Delete |
GET | /api/prompt/{id}/versions | Auth | History |
POST | /api/prompt/{id}/restore/{versionId} | Admin | Restore |
{
"projectId": 1,
"name": "Intake",
"systemPrompt": "You are an intake assistant…",
"userPrompt": null,
"isActive": true,
"temperature": 0.3,
"maxTokens": 2000
}
4.6 Providers
Controller: ProviderController (api/Provider) — JWT; writes Admin
| Method | Path | Purpose |
|---|---|---|
GET | /api/provider | List |
GET | /api/provider/{id} | Detail |
POST / PUT / DELETE | /api/provider[/{id}] | CRUD (Admin) |
PATCH | /api/provider/{id}/status | Enable/disable |
POST | /api/provider/{id}/set-default | Set default |
POST | /api/provider/discover-models | Discover models |
GET | /api/provider/{id}/models | Models |
GET | /api/provider/{id}/usage / /api/provider/usage | Usage |
Types include: Azure, Bedrock, Gemini, Ollama, OpenAI-compatible, KnowledgeBase (KbBackend: AzureSearch | Internal), AzureRealtime.
Capability flags: text / audio / document / image / agentTools / embeddings / realtime audio.
For Internal RAG: enable Embeddings on an Azure or Gemini provider, create a Knowledge Base, then create a KnowledgeBase provider with KbBackend=Internal linked to that base — or ground chat via knowledgeBaseIds on /api/ai/chat.
4.7 Knowledge Bases
Kroov supports internal knowledge bases backed by PostgreSQL pgvector (and durable object storage: Azure Blob or GCS). Azure AI Search remains available as a provider KbBackend.
Runtime requirements: PostgreSQL + vector extension, KnowledgeBase:Internal:Enabled, embedding provider (Azure/Gemini with SupportsEmbeddings), storage provider configured. Otherwise KB admin APIs return 503.
Deep dive: docs/INTERNAL-RAG.md.
Admin CRUD — KnowledgeBasesController (api/knowledge-bases) — AdminOnly
| Method | Path | Purpose |
|---|---|---|
GET | /api/knowledge-bases?projectId= | List |
GET | /api/knowledge-bases/{id} | Detail |
POST | /api/knowledge-bases | Create |
PUT | /api/knowledge-bases/{id} | Update |
DELETE | /api/knowledge-bases/{id} | Delete base + storage + chunks |
PUT | /api/knowledge-bases/{id}/projects | Share with additional projects { "projectIds": [1,2] } |
GET | /api/knowledge-bases/{id}/documents?page&pageSize&search&status | List documents |
POST | /api/knowledge-bases/{id}/documents | Upload (multipart, field files) — pdf/docx/xlsx/xls/csv/txt |
POST | /api/knowledge-bases/{id}/documents/{documentId}/reindex | Reindex |
GET | /api/knowledge-bases/{id}/documents/{documentId}/content | Download original |
DELETE | /api/knowledge-bases/{id}/documents/{documentId} | Delete document |
Create / update body:
{
"projectId": 1,
"name": "Team Protocols",
"embeddingProviderId": 3,
"embeddingModel": "text-embedding-3-small",
"chunkSize": 1000,
"chunkOverlap": 100,
"isActive": true
}
Document lifecycle: Pending → Extracting → Embedding → Indexed (or failed with error; reindex supported). Ingestion uses FOR UPDATE SKIP LOCKED leases across API replicas.
Upload example:
curl -X POST https://your-kroov-host/api/knowledge-bases/3/documents \
-H "Authorization: Bearer $ADMIN_JWT" \
-F "files=@protocol.pdf" \
-F "files=@checklist.docx"
Project picker — ProjectKnowledgeBasesController
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/projects/{projectId}/knowledge-bases | JWT (project access) | Read-only list of own + shared bases for chat/agent UI |
Using knowledge in inference
- KnowledgeBase provider — create a provider of type KnowledgeBase with
KbBackend=InternalandinternalKnowledgeBaseId; query it like any other provider. - Chat grounding — on
POST /api/ai/chat, passknowledgeBaseIds: […]with a normal text model; retrieved chunks are injected as server context with[ref_id:N]citation markers. - Embeddings API —
POST /v1/embeddingsfor the same embedding pipeline. - Scheduled tasks / sessions — pass allow-listed
knowledgeBaseIdssoknowledge_base_searchmay only search those bases (empty list = no restriction).
Blob URLs in citations are opened via /api/ai/download-blob or /api/ai/view-blob with the API key.
4.8 MCP Platform
Kroov exposes a full MCP control plane: remote HTTP MCPs, catalog install, Kubernetes-backed managed runtimes, per-user OAuth vault, federation entitlements, definitions/diagnostics, and an internal runtime proxy.
| Surface | Auth |
|---|---|
api/mcp-servers, definitions, credentials | JWT (writes mostly Admin) |
api/mcp-catalog, api/mcp-runtime | JWT Admin (+ hosted runtime attribute) |
api/mcp-instances | JWT or delegation; requires hosted MCP runtimes |
api/integrations | JWT (OAuth connect for end users) |
api/mcp-runtime-proxy | X-Mcp-Controller-Token (AllowAnonymous + token check) |
api/delegations/exchange | Project API key + service/user tokens |
| Chat with MCP tools | Project API key (+ optional user/delegation headers) |
Concepts
Transport types (transportType):
| Value | Name | Usage |
|---|---|---|
0 | HttpOpenApi | Deprecated — OpenAPI bridge |
1 | McpStreamableHttp | Native MCP over HTTP (preferred) |
2 | McpStdio | Stdio profile (catalog custom images; not JSON-importable) |
Credential types (credentialType): None, Passthrough, OAuth, Pat, EnvVar.
Remote vs managed: Remote MCPs call a vendor URL. Managed MCPs run as isolated Kubernetes worker pods; chat targets mcpInstanceId whose endpoint is routed through the internal proxy.
MCP servers — McpServerController (api/mcp-servers)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/mcp-servers | Auth | List (non-admins: active only) |
GET | /api/mcp-servers/{id} | Auth | Detail + tools |
POST / PUT / DELETE | /api/mcp-servers[/{id}] | Admin | CRUD |
PUT | /api/mcp-servers/{id}/tools/{toolId} | Admin | Enable/disable tool |
POST | /api/mcp-servers/import/preview | Admin | Preview JSON config |
POST | /api/mcp-servers/import | Admin | Install from JSON (+ optional one-shot credential) |
POST | /api/mcp-servers/{id}/sync-tools | Admin | Native MCP tool discovery |
POST | /api/mcp-servers/{id}/import-openapi | Admin | Legacy HttpOpenApi |
GET / PUT | /api/projects/{projectId}/mcp-servers | Auth / Admin | Project assignments |
PUT | /api/mcp-servers/{id}/projects | Admin | Set this server’s projects (non-destructive) |
Profile fields: name, baseUrl, description, transportType, remoteEndpointUrl, registryServerName, registryVersion, stdioCommand, stdioArgsJson, stdioEnvVarKeysJson, authMode, contextMode, requireCredential, credentialType, oauthProviderKey, authHeaderName, authHeaderTemplate (must contain {credential} when required), allowedHosts, allowedPathPrefix, defaultMaxToolRounds, defaultMaxToolCalls, isActive.
Remote Streamable HTTP create:
curl -X POST https://your-kroov-host/api/mcp-servers \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "SerpAPI",
"baseUrl": "https://mcp.serpapi.com/{credential}/mcp",
"transportType": 1,
"remoteEndpointUrl": "https://mcp.serpapi.com/{credential}/mcp",
"credentialType": 3,
"requireCredential": true,
"authMode": 2
}'
JSON import (Claude Desktop / Cursor / VS Code mcpServers shape). Stdio/npx entries are rejected for JSON import — use Catalog → Custom for containerised MCPs.
{
"json": "{ \"mcpServers\": { \"gmail\": { \"serverUrl\": \"https://gmailmcp.googleapis.com/mcp/v1\", \"oauth\": { \"clientId\": \"…\", \"clientSecret\": \"…\" } } } }",
"credential": "optional-one-shot-pat"
}
Sync tools:
curl -X POST .../api/mcp-servers/12/sync-tools \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{ "credential": "sk-live-..." }'
→ { "synced": 15 }
Catalog — McpCatalogController (api/mcp-catalog) — AdminOnly
source query: github (default) or custom (pre-built K8s images).
| Method | Path | Purpose |
|---|---|---|
GET | /api/mcp-catalog?search=&source=&page=&pageSize= | Search (auto-sync) |
GET | /api/mcp-catalog/{serverName}?source= | Detail |
POST | /api/mcp-catalog/refresh?source= | Force sync |
POST | /api/mcp-catalog/{serverName}/install?source= | Install (+ tool sync for remote) |
Custom install may return managedRuntime: true, runtimeProfileId, requiresPairing.
Definitions & credentials — McpDefinitionController
Under /api/mcp-servers/{id}/…:
| Method | Path | Purpose |
|---|---|---|
GET / PUT | /definition | Canonical definition |
POST | /definition/validate | Validate |
GET | /definition/export?format= | Export |
GET | /definition/revisions[/{rev}] | History |
POST | /definition/revisions/{rev}/restore | Restore |
GET | /credential-requirements | What creds are needed |
GET | /credential-status | Status for account/project |
PUT / DELETE | /credentials/{accountName} | Vault set/delete |
POST | /diagnostics/{validate|discover-oauth|test-connection|list-tools} | Admin diagnostics |
Managed instances — McpInstanceController (api/mcp-instances)
Requires hosted MCP runtimes (Kubernetes:Enabled). Attribute [RequiresHostedMcpRuntimes] → 503 otherwise.
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/mcp-instances | List / create (Idempotency-Key optional) |
GET | /{id} | Detail + availableActions |
GET | /{id}/pairing | WhatsApp QR (Cache-Control: no-store) |
POST | /{id}/restart | /suspend | /resume | /reassociate | Lifecycle |
GET / POST / DELETE | /{id}/grants[/{grantId}] | Instance grants |
DELETE | /{id} | Delete worker + row |
POST | /{id}/runtime-status | AllowAnonymous — worker → API status callback |
{ "mcpServerId": 5, "projectId": 1, "ownerUserId": 2, "ownerExternalPrincipalId": null }
Statuses: Requested, Provisioning, AwaitingPairing, Ready, Degraded, Suspended, PairingRejected, Deleting, Deleted.
Federated callers use X-AINexus-Delegation with scopes such as mcp:pair, mcp:invoke, mcp:manage.
Runtime profiles — McpRuntimeController (api/mcp-runtime) — Admin + hosted runtimes
| Method | Path | Purpose |
|---|---|---|
POST | /api/mcp-runtime/analyze | Preview npx/stdio → generic runtime |
POST | /api/mcp-runtime/register | Register (hostingMode: container | subprocess Dev-only) |
GET | /api/mcp-runtime/{id} | Profile status |
POST | /api/mcp-runtime/{id}/rebuild | Kaniko rebuild |
Runtime proxy — McpRuntimeProxyController (api/mcp-runtime-proxy)
Internal data-plane proxy to the worker pod via the Kubernetes API:
GET|POST|DELETE /api/mcp-runtime-proxy/{instanceId}/mcp/
Auth: header X-Mcp-Controller-Token must equal Kubernetes:ControllerToken / McpRuntime:ControllerToken.
User OAuth / PAT integrations — IntegrationAuthController (api/integrations)
| Method | Path | Purpose |
|---|---|---|
GET | /api/integrations/mine | User’s stored credentials |
GET | /api/integrations/available | Connectable MCP servers + connected? |
GET | /api/integrations/{mcpServerId}/connect?returnTo= | { "authorizeUrl" } |
GET | /api/integrations/{provider}/callback | OAuth callback → SPA |
PUT | /api/integrations/{mcpServerId}/token | Store PAT { "token": "…" } |
DELETE | /api/integrations/{mcpServerId}/disconnect | Revoke |
Provider keys include Google and GitHub. Client secrets are never returned in API responses.
Chat credential resolution order
- Inline
delegation.credential - OAuth / PAT vault for the authenticated user (
/api/integrations) - Managed instance via
delegation.mcpInstanceId(phone match enforced for WhatsApp federated users)
4.9 Agents & Environments
Configurable agents are project-scoped definitions used by:
- Interactive chat (
agentDefinitionIdon/api/ai/chat) - Event automations (must name an agent)
- Headless Kubernetes Jobs (development agents with repository / setup / build / test)
- Scheduled tasks targeting
AgentRun
Deep dive: docs/CONFIGURABLE-AGENTS.md.
Agents — AgentsController (api/agents) — JWT
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/agents?projectId= | Project member | List (+ automation counts) |
GET | /api/agents/{id} | Member | Detail |
POST | /api/agents | Member | Create config agent |
PUT / DELETE | /api/agents/{id} | Member* | Update / delete (*dev agents with repository: Admin only) |
POST | /api/agents/development-template | Admin | Seed K8s dev agent (setup/build/test) |
GET / POST / PUT / DELETE | /api/agents/{id}/schedules… | Admin | Legacy agent cron schedules |
POST | /api/agents/{id}/runs | Admin | Queue K8s Job (Agents:Enabled or 503) |
GET / POST / DELETE | /api/agents/{id}/grants… | Member | Tool grants (not gated on Automations) |
Create config agent (automations / chat):
{
"projectId": 1,
"name": "Support agent",
"description": null,
"providerId": null,
"systemPrompt": "You are a support agent. Read the customer message and draft a reply.",
"temperature": 0.2,
"isActive": true,
"mcpServerIds": [12],
"mcpAccountNames": { "12": "default" }
}
Member-facing CRUD cannot author RepositoryUrl, BaseBranch, setup/build/test commands, or budget fields — those are Admin / development-template concerns.
Start run:
{
"task": "Fix failing tests",
"idempotencyKey": "manual:abc",
"deliveryTarget": "PullRequest",
"gitHubInstallationId": 4287162
}
Tool grant:
{
"integrationConnectionId": "…",
"toolName": "pipedream__slack__send_message",
"externalActionKey": null,
"actionClass": "ExternalCommunication",
"allowedResourcePattern": "#support",
"maxCallsPerRun": 1,
"requiresApproval": true
}
Environments — AgentEnvironmentsController (api/agent-environments) — Admin
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/agent-environments | List / create profiles |
GET / PUT / DELETE | /{id} | CRUD |
POST | /ensure-universal | Ensure shared universal profile |
GET / POST | /prewarm | Workspace image coverage / prewarm |
Profiles override image, storage, CPU, memory, and declared egress hosts.
4.10 Agent Runs (headless Jobs)
Controller: AgentRunsController (api/agent-runs) — Admin (Roles=Admin)
Requires Agents:Enabled + Kubernetes for execution. Runs are queued in PostgreSQL, leased, provisioned as Jobs in namespace agent-runs, and streamed via append-only events.
| Method | Path | Purpose |
|---|---|---|
GET | /api/agent-runs?agentId= | List (≤200) |
GET | /{id} | Run + artifacts summary |
GET | /{id}/events?after= | SSE resumable event stream |
POST | /{id}/input | { "input": "…" } when WaitingForInput |
POST | /{id}/cancel | Cancel |
POST | /{id}/retry | Retry |
GET | /{id}/artifacts | Artifacts |
POST | /{id}/memory/{memoryId}/{decision} | Memory review |
curl -N "https://your-kroov-host/api/agent-runs/42/events?after=0" \
-H "Authorization: Bearer $ADMIN_JWT"
4.11 Interactive Sessions
Controller: AgentSessionsController (api/sessions) — JWT (any authenticated user)
Feature bit: agentSessions = AgentSessions:Enabled && Kubernetes:Enabled
Sessions provision a persistent workspace pod (+ PVC). They can clone a GitHub repository or start empty (general-purpose) when both repositoryFullName and repositoryUrl are omitted. projectId remains required (security, billing, provider, MCP boundary).
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/sessions | List / create |
GET | /{id} | Detail |
GET | /{id}/usage | Lifetime + per-turn usage |
POST | /{id}/messages | { "message": "…" } |
POST | /{id}/files | Multipart uploads (files) |
POST | /{id}/transcribe | Multipart audio → text (audio) |
PATCH | /{id}/settings | provider/model/mode/budgets |
POST | /{id}/messages/edit | Edit + rerun from sequence |
POST | /{id}/compact | Manual context compaction |
POST | /{id}/cancel | Cancel in-flight turn |
POST | /{id}/stop | Stop session |
DELETE | /{id} | Tear down pod + PVC + history |
GET | /{id}/files?path= | Download workspace file (≤25 MB; paths under /workspace/repository or /workspace/uploads) |
GET | /{id}/export | ZIP export (≤50 MB, excludes .git) |
GET | /{id}/diagnostics | K8s provisioning diagnostics |
GET | /{id}/diff / /{id}/changes | Git diff / changed files |
GET | /{id}/events?after= | SSE event stream |
Create:
{
"projectId": 1,
"repositoryFullName": "org/repo",
"repositoryUrl": "https://github.com/org/repo",
"branch": "main",
"gitHubInstallationId": 1,
"environmentProfileKey": "universal",
"providerId": 12,
"model": null,
"title": "Investigate flake",
"firstMessage": "Find why CI fails on main"
}
Omit both repository fields for an empty workspace (still requires projectId). Supplying one repository field requires both.
Settings patch:
{
"providerId": 12,
"model": "gpt-4o",
"mode": "Agent",
"maxInputContextTokens": 128000,
"maxTokens": 500000,
"maxEstimatedCostUsd": 25
}
Modes typically include Agent (read/write tools), Plan, and Ask (read-only tool sets).
Usage semantics: lifetime counters are TotalTurns, ActiveMs, TotalModelCalls, TotalToolCalls, InputTokens, OutputTokens. Per-turn guards ModelCalls / ToolCalls reset each turn — do not use them for lifetime reporting.
MCP tools assigned to the project (with the user’s credential/grant) are resolved automatically for interactive sessions.
4.12 Scheduled Tasks
Controller: ScheduledTasksController (api/scheduled-tasks) — JWT, user-scoped (personal, not admin-global)
Requires ScheduledTasks:Enabled && AgentSessions:Enabled (create/update → 503 otherwise). Feature bit also needs Kubernetes because tasks execute as sessions (or agent runs).
Deep dive: docs/AUTONOMOUS-SCHEDULED-TASKS.md.
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/scheduled-tasks | List / create |
GET / PUT / DELETE | /{id} | CRUD (update re-bases schedule) |
POST | /{id}/pause | /resume | /run-now | Control |
GET | /{id}/occurrences?take&skip | History |
GET | /occurrences/{occurrenceId} | Occurrence + report |
POST | /occurrences/{occurrenceId}/cancel | Cancel live run |
DELETE | /occurrences/{occurrenceId} | Delete finished history |
GET | /preview-schedule?… | Dry-run next N slots |
Targets:
target | Behaviour |
|---|---|
Session (default) | Each firing creates a fresh AgentSession with the task’s mode, provider, allow-lists, budgets |
AgentRun | Queues an AgentRun against an existing AgentDefinition |
Recurrence: exactly one of intervalMinutes (anchored on startAtUtc) or cronExpression + timeZoneId (5-field cron).
Create body (selected fields):
{
"name": "Nightly TODO sweep",
"instructions": "Collect TODOs and propose a cleanup plan.",
"projectId": 1,
"description": null,
"isActive": true,
"target": "Session",
"providerId": 12,
"model": null,
"mode": "Plan",
"knowledgeBaseIds": [3],
"mcpServerIds": [12],
"repositoryFullName": "org/repo",
"repositoryUrl": "https://github.com/org/repo",
"branch": "main",
"gitHubInstallationId": 1,
"intervalMinutes": 1440,
"cronExpression": null,
"timeZoneId": "Asia/Jerusalem",
"startAtUtc": "2026-08-09T02:00:00Z",
"endAtUtc": null,
"overlapPolicy": "Skip",
"maxConsecutiveFailures": 3,
"carryOverPreviousReport": true,
"maxTokens": 200000,
"maxEstimatedCostUsd": 5,
"maxToolCallsPerTurn": 40,
"maxModelCallsPerTurn": 40,
"reportEnabled": true
}
Safety rails: overlap Skip/Queue, unique idempotency per slot, auto-pause after consecutive failures, per-occurrence budgets, per-user concurrency caps, workspace teardown after run, DST-aware cron.
Reports: every occurrence ends with ReportMarkdown (narrative + trusted metrics footer), streamed as a report event and stored on the occurrence. Failed/cancelled runs still get a report.
Empty knowledgeBaseIds / mcpServerIds means no restriction (same as interactive sessions).
4.13 Automations, Connections & Approvals
Event automations wake an agent on an external event (Slack message, Shopify order, …) rather than on a schedule or interactive user. They run on an in-process Service runtime and do not require Kubernetes.
Enable with:
export Automations__Enabled=true
export Automations__PublicWebhookBaseUrl=https://your-kroov-host
# Optional Pipedream Connect
export Automations__Pipedream__ProjectId=proj_...
export Automations__Pipedream__ClientId=...
export Automations__Pipedream__ClientSecret=...
When Automations:Enabled=false, automation controllers return 503.
Walkthrough with duplicate-delivery assertions: docs/automations-demo.md.
Concepts
| Entity | Role |
|---|---|
| IntegrationConnection | Linked external account + webhook URL + signing secret |
| Automation | Project-scoped rule: agent + connection + event type + instructions + execution mode |
| InboundEvent | Signed webhook delivery (deduped by external delivery id) |
| Invocation | One agent run for an event (Pending → Running → WaitingForApproval / terminal) |
| Approval | Human gate for write/send tool calls |
| Grant | Allow-listed tool with optional resource pattern + approval flag |
Execution modes (AutomationExecutionMode):
| Mode | Behaviour |
|---|---|
Observe | Read-only observation of events |
Draft | Agent may draft; nothing leaves the system |
ApproveWrites | Reads run immediately; mutating/external actions require approval |
ScopedAutonomous | Allowed granted actions may execute within grant limits without per-action approval |
Interactive | Reserved for human-watched agent chat invocations (not used by webhook dispatch) |
Action classes (AgentActionClass): ReadOnly, ReversibleWrite, ExternalCommunication, Financial, Destructive, CredentialOrPermissionChange.
Runtime kinds (AgentRuntimeKind): Service (in-process automations — default for event automations), Workspace, Workflow.
Pipedream Connect — PipedreamConnectController (api/integrations/pipedream) — JWT
| Method | Path | Purpose |
|---|---|---|
POST | /connect-token | { "projectId" } → Connect token (external user id from principal, never body) |
GET | /apps?query= | Search apps |
GET | /apps/{appKey}/actions | List actions |
POST | /connections | Record account; webhookSecret returned once |
GET | /accounts?projectId&appKey | Pipedream accounts for user |
GET | /connections | Local IntegrationConnections |
POST | /connections/{id}/rotate-secret | Rotate signing secret |
DELETE | /connections/{id} | Revoke |
curl -s -X POST https://your-kroov-host/api/integrations/pipedream/connect-token \
-H "Authorization: Bearer $JWT" -H 'Content-Type: application/json' \
-d '{"projectId":1}'
curl -s -X POST https://your-kroov-host/api/integrations/pipedream/connections \
-H "Authorization: Bearer $JWT" -H 'Content-Type: application/json' \
-d '{"projectId":1,"appKey":"slack","accountId":"apn_abc123"}'
{
"connection": {
"id": "…",
"webhookUrl": "https://…/api/integration-events/pipedream/…"
},
"webhookSecret": "…"
}
Store webhookSecret immediately — it is encrypted at rest and never returned again (except via rotate).
Webhook gateway — IntegrationEventsController — AllowAnonymous
POST /api/integration-events/{provider}/{connectionId}
- Connection id is in the path (routing key); signing secret belongs to that connection alone.
- Pipedream: header
x-pd-signatureover the raw body. - Success: 202 Accepted.
- Unknown connection or bad signature → identical 401 (no connection-id oracle).
- Duplicate delivery id →
{ "duplicate": true, "deliveryId": "…" }with no second side effects.
Automations CRUD — AutomationsController (api/automations) — JWT (project-scoped)
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/automations | List / create |
GET / PUT / DELETE | /{id} | CRUD |
POST | /{id}/toggle | { "isActive": true } — new automations start paused |
GET | /{id}/invocations | Invocation history |
GET / POST / DELETE | /{id}/grants… | Tool grants |
{
"projectId": 1,
"agentDefinitionId": 1,
"integrationConnectionId": "<guid>",
"name": "Support inbox",
"eventType": "message",
"instructions": "Read the customer message and draft a reply.",
"runtimeKind": "Service",
"executionMode": "ApproveWrites",
"maxEventsPerHour": 60,
"maxConcurrentRuns": 1
}
{
"toolName": "pipedream__slack__send_message",
"actionClass": "ExternalCommunication",
"allowedResourcePattern": "#support",
"maxCallsPerRun": 1,
"requiresApproval": true
}
An automation must reference an existing agent (POST /api/agents first). Service runtime agents do not need a repository or K8s.
Events inbox — AutomationEventsController (api/automation-events) — JWT
| Method | Path | Purpose |
|---|---|---|
GET | /api/automation-events?projectId&status&take | Inbox |
GET | /dead-letter | Dead letter |
GET | /{id} | Event + invocations chain |
POST | /{id}/replay | New attempt (bumps attempt count) |
POST | /{id}/ignore | Ignore |
POST | /test | Development only — sign a test delivery with the connection’s secret |
{
"connectionId": "…",
"eventType": "message",
"payloadJson": "{\"event_id\":\"evt_1\",\"text\":\"where is my order?\"}"
}
/test returns the URL, headers, and body to POST to the real gateway.
Approvals — AutomationApprovalsController (api/automation-approvals) — JWT
| Method | Path | Purpose |
|---|---|---|
GET | /api/automation-approvals?status= | List |
GET | /{id} | Detail |
POST | /{id}/approve | { "comment": "…" } — records decision; ActionWorker executes |
POST | /{id}/reject | { "comment": "…" } |
A second approve returns 409 (exactly-once action execution).
4.14 GitHub App Integration
Controller: GitHubController (api/integrations/github) — JWT (setup callback anonymous)
Used by sessions and agent runs to list installations/repos/branches and clone via the GitHub App.
| Method | Path | Purpose |
|---|---|---|
GET | /status | App configured? |
GET | /installations | Linked installations + repos |
GET | /discover | Relinkable prior installs |
POST | /link | Relink installation |
GET | /connect | Start GitHub App install |
GET | /setup | Anon callback (installation_id, state) |
GET | /repos | Repos available for agent clone |
GET | /repos/{owner}/{repo}/branches?installationId= | Branches |
DELETE | /{installationId}/disconnect | Unlink |
4.15 Cost, Dashboard & Logs
Cost — CostController (api/Cost) — JWT
| Method | Path | Query |
|---|---|---|
GET | /api/cost/by-request-type | projectId?, days? |
GET | /api/cost/by-provider | idem |
GET | /api/cost/by-project | idem |
GET | /api/cost/by-request | pagination |
GET | /api/cost/summary |
Dashboard — DashboardController (api/Dashboard) — JWT
| Method | Path | Purpose |
|---|---|---|
GET | /api/dashboard/prompt-stats | Prompt usage |
GET | /api/dashboard/token-usage | Tokens |
GET | /api/dashboard/provider-stats | Per provider |
GET | /api/dashboard/summary | Overview |
GET | /api/dashboard/logs | Log list |
GET | /api/dashboard/logs/{id} | Log detail |
API-key scoped logs also available at GET /api/ai/logs.
4.16 Security & Health
Security — SecurityController (api/security)
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /api/security/status | AdminOnly | Security mode, audit, CSP, payload writer status |
POST | /api/security/csp-report | Anonymous | Browser CSP violation reports (204) |
Health
curl -s https://your-kroov-host/health
# { "status": "healthy" }
5. Request & Response Formats
5.1 Standard Request Format
API Key (AI / OpenAI-compat):
x-api-key: your-api-key-here
Content-Type: application/json
JWT (SPA / admin / agents):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Body (JSON, camelCase):
{
"prompt": "Your query here",
"projectId": 1,
"providerId": 12,
"stream": false
}
5.2 Standard AI Response Format
Success:
{
"success": true,
"content": "AI response text here",
"errorMessage": null,
"provider": "Azure",
"providerId": 12,
"executionDuration": "00:00:02.345",
"requestId": 12345,
"inputTokens": 25,
"outputTokens": 150
}
Validation / problem details may also use ASP.NET Core’s default error shapes (title, errors, traceId) on admin APIs.
5.3 Response Fields (AI)
| Field | Type | Description |
|---|---|---|
success | boolean | Outcome |
content | string | Model text (null on error) |
errorMessage | string | Error description |
provider | string | Provider type used |
providerId | integer | Instance id |
executionDuration | string | HH:mm:ss.fff |
requestId | integer | For logging / voting |
inputTokens / outputTokens | integer | Token counts |
audioDuration | number | Seconds (audio) |
chatId | GUID string | Chat session |
messageIndex | integer | Turn index |
sessionEnded | boolean | Chat closed |
5.4 File Upload Format
Content-Type: multipart/form-data. Field names are camelCase (providerId, projectId, noLog, files, audio, …).
curl -X POST https://your-kroov-host/api/ai/queryImage \
-H "x-api-key: your-api-key" \
-F "file=@image.png" \
-F "prompt=Analyze this image" \
-F "projectId=1" \
-F "providerId=12"
6. Streaming API
6.1 Server-Sent Events (SSE)
Used by:
| Surface | Endpoint | Auth |
|---|---|---|
AI chat / query (stream: true) | POST /api/ai/chat or /query | API Key |
| Agent runs | GET /api/agent-runs/{id}/events?after= | Admin JWT |
| Interactive sessions | GET /api/sessions/{id}/events?after= | JWT |
Headers (client):
Accept: text/event-stream
Typical AI chat events:
| Event / data | Meaning |
|---|---|
content | Text delta |
toolCalls | Tool invocations / results |
status | Round progress |
tokens | Cumulative token counts |
error | Terminal error |
[DONE] | Stream end |
Resumable streams (runs / sessions): pass after=<lastEventId> to continue after reconnect.
6.2 Client-Side Handling (AI SSE)
const response = await fetch('https://your-kroov-host/api/ai/chat', {
method: 'POST',
headers: {
'x-api-key': apiKey,
'Content-Type': 'application/json',
'Accept': 'text/event-stream'
},
body: JSON.stringify({
messageUser: 'Summarize the key points',
projectId: 1,
providerId: 12,
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data:')) continue;
const data = line.slice(5).trim();
if (data === '[DONE]') return;
try {
const evt = JSON.parse(data);
if (evt.content) process.stdout?.write?.(evt.content);
} catch { /* ignore keep-alives */ }
}
}
6.3 WebSocket realtime STT
See WebSocket — Live realtime transcription under §4.1.
7. Error Handling
7.1 HTTP Status Codes
| Code | Meaning | Typical cause |
|---|---|---|
200 | OK | Success |
202 | Accepted | Webhook accepted for async processing |
204 | No Content | CSP report stored |
400 | Bad Request | Validation / malformed body |
401 | Unauthorized | Missing/invalid API key, JWT, webhook signature, unknown connection |
403 | Forbidden | Project access denied; non-admin on AdminOnly route |
404 | Not Found | Unknown id |
409 | Conflict | Duplicate name; second approval; optimistic conflict |
413 | Payload Too Large | Upload over limit |
429 | Too Many Requests | If rate limiting is enabled in a given deployment |
500 | Internal Server Error | Unexpected failure |
502 | Bad Gateway | Upstream AI provider failure |
503 | Service Unavailable | Feature disabled / KB not supported / hosted MCP unavailable |
7.2 Feature-gate 503 examples
{ "error": "Event automations are disabled on this deployment." }
{ "message": "Internal knowledge bases require PostgreSQL with pgvector." }
Call GET /api/features before enabling UI affordances.
7.3 Retry Strategy
| Status | Retry? | Guidance |
|---|---|---|
408 / 429 / 502 / 503 | Yes | Exponential backoff with jitter |
500 | Cautious | Retry idempotent GETs; use idempotency keys on creates where supported |
400 / 401 / 403 / 404 / 409 | No | Fix request / credentials |
Idempotency:
- MCP instance create: optional
Idempotency-Keyheader - Agent runs:
idempotencyKeyin body - Scheduled task occurrences: unique
(ScheduledTaskId, IdempotencyKey)per slot - Automation webhooks: dedupe on external delivery id
7.4 Error Logging
Always capture: HTTP status, requestId (when present), correlation / trace id, timestamp, endpoint, project id. Never log API keys, JWTs, webhook secrets, or raw sensitive data beyond what your compliance policy allows.
8. Code Examples
8.1 JavaScript / TypeScript — reusable AI client
type AiQueryOptions = {
promptId?: number;
provider?: string;
providerId?: number;
stream?: boolean;
externalId?: string;
externalUser?: string;
noLog?: boolean;
knowledgeBaseIds?: number[];
agentDefinitionId?: number;
};
class KroovClient {
constructor(
private readonly baseUrl: string,
private readonly apiKey: string
) {}
async query(prompt: string, projectId: number, options: AiQueryOptions = {}) {
const response = await fetch(`${this.baseUrl}/api/ai/query`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ prompt, projectId, stream: false, ...options })
});
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw new Error(err.errorMessage || `HTTP ${response.status}`);
}
return response.json();
}
async chat(
messageUser: string,
projectId: number,
options: AiQueryOptions & { chatId?: string | null; delegation?: object } = {}
) {
const response = await fetch(`${this.baseUrl}/api/ai/chat`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ messageUser, projectId, stream: false, ...options })
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
return response.json();
}
async *streamChat(messageUser: string, projectId: number, options: Record<string, unknown> = {}) {
const response = await fetch(`${this.baseUrl}/api/ai/chat`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json',
Accept: 'text/event-stream'
},
body: JSON.stringify({ messageUser, projectId, stream: true, ...options })
});
if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data:')) continue;
const data = line.slice(5).trim();
if (data === '[DONE]') return;
try { yield JSON.parse(data); } catch { /* keep-alive */ }
}
}
}
}
// Usage
const client = new KroovClient('https://your-kroov-host', process.env.AINEXUS_API_KEY!);
const result = await client.query('Summarize the key points', 1, { providerId: 12 });
console.log(result.content);
8.2 Python — chat with knowledge bases + streaming
import json
import requests
BASE = "https://your-kroov-host"
def chat(api_key: str, message: str, project_id: int, kb_ids: list[int], chat_id: str | None = None):
r = requests.post(
f"{BASE}/api/ai/chat",
headers={"x-api-key": api_key, "Content-Type": "application/json"},
json={
"messageUser": message,
"projectId": project_id,
"chatId": chat_id,
"knowledgeBaseIds": kb_ids,
"stream": False,
},
timeout=120,
)
r.raise_for_status()
return r.json()
def stream_query(api_key: str, prompt: str, project_id: int, provider_id: int | None = None):
with requests.post(
f"{BASE}/api/ai/query",
headers={"x-api-key": api_key, "Content-Type": "application/json"},
json={"prompt": prompt, "projectId": project_id, "providerId": provider_id, "stream": True},
stream=True,
timeout=300,
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if not line or not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
try:
evt = json.loads(data)
except json.JSONDecodeError:
continue
if content := evt.get("content"):
print(content, end="", flush=True)
8.3 C# — OpenAI-compatible client
using var http = new HttpClient { BaseAddress = new Uri("https://your-kroov-host") };
http.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
var payload = new {
model = "gpt-4o",
messages = new[] { new { role = "user", content = "Summarize the key guidance" } },
extension = new { noLog = false }
};
var res = await http.PostAsJsonAsync("/v1/chat/completions", payload);
res.EnsureSuccessStatusCode();
var json = await res.Content.ReadAsStringAsync();
8.4 cURL — automation happy path (dev)
TOKEN=$(curl -s -X POST https://localhost:7003/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}' | jq -r .token)
AUTH="Authorization: Bearer $TOKEN"
# 1) Agent
AGENT_ID=$(curl -s -X POST https://localhost:7003/api/agents \
-H "$AUTH" -H 'Content-Type: application/json' \
-d '{"projectId":1,"name":"Support agent","systemPrompt":"Draft replies."}' | jq -r .id)
# 2) After Pipedream Connect UI records a connection:
# curl -s -X POST https://localhost:7003/api/automations -H "$AUTH" -H 'Content-Type: application/json' -d '{...}'
# curl -s -X POST https://localhost:7003/api/automations/$ID/grants -H "$AUTH" ...
# curl -s -X POST https://localhost:7003/api/automations/$ID/toggle -H "$AUTH" -d '{"isActive":true}'
# curl -s -X POST https://localhost:7003/api/automation-events/test -H "$AUTH" -d '{...}'
# Full script: docs/automations-demo.md
8.5 cURL — create interactive session (empty workspace)
curl -s -X POST https://localhost:7003/api/sessions \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"projectId": 1,
"providerId": 12,
"title": "Scratch workspace",
"firstMessage": "Create a short project plan markdown file"
}'
8.6 cURL — knowledge base upload + chat grounding
# Admin JWT required for KB admin APIs
curl -s -X POST https://localhost:7003/api/knowledge-bases \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"projectId": 1,
"name": "Protocols",
"embeddingProviderId": 3,
"embeddingModel": "text-embedding-3-small",
"chunkSize": 1000,
"chunkOverlap": 100,
"isActive": true
}'
curl -s -X POST https://localhost:7003/api/knowledge-bases/1/documents \
-H "Authorization: Bearer $TOKEN" \
-F "files=@protocol.pdf"
# Inference uses API key + knowledgeBaseIds (after documents reach Indexed)
curl -s -X POST https://localhost:7003/api/ai/chat \
-H "x-api-key: $API_KEY" -H 'Content-Type: application/json' \
-d '{
"messageUser": "What does the protocol say about escalation?",
"projectId": 1,
"providerId": 12,
"knowledgeBaseIds": [1]
}'
9. Best Practices
9.1 API Key & JWT Management
- Prefer API keys for service-to-service AI calls; JWT for user-context admin/agent operations
- Scope keys to a project when possible
- Rotate keys; revoke immediately on compromise
- Use refresh tokens; never embed long-lived JWTs in mobile binaries without a refresh flow
9.2 Provider Routing
- Prefer
providerIdfor deterministic routing and cost attribution - Check capability flags (text/image/audio/embeddings/agentTools/realtime) before calling
- Keep a fallback provider strategy client-side for
502responses
9.3 Chat & MCP
- Use
stream: truefor tool-using chats - Constrain tools with project MCP assignments + per-user credentials + grants
- For multi-MCP, set
delegation.mcpServerIdsexplicitly; use[]only when you intentionally want grants-only tools - Never put long-lived vendor secrets in client-side code — use the vault (
/api/integrations) or managed instances
9.4 Knowledge Bases
- Chunk size / overlap defaults are fine for most corpora; reindex after embedding model changes
- Share bases across projects via
PUT .../projectsinstead of duplicating uploads - Use
knowledgeBaseIdson chat for ad-hoc grounding without a dedicated KB provider
9.5 Agents, Sessions & Tasks
- Start autonomous work in
PlanorAskmode before enabling write tools - Set budgets (
maxTokens,maxEstimatedCostUsd, tool/model call caps) on sessions and scheduled tasks - Prefer
overlapPolicy: Skipfor scheduled tasks unless concurrent work is intentional - Export session artifacts (
/export) beforeDELETEif you need the files
9.6 Automations
- Create automations paused, add grants, then
toggleactive - Prefer
ApproveWritesfor anything that sends external messages - Treat webhook secrets like passwords; rotate with
/rotate-secret - Rely on platform dedupe — still design handlers to be safe under at-least-once delivery
9.7 Performance & Resilience
- Reuse
chatIdinstead of resending full history viamessageHistorywhen possible - Use resumable SSE (
after=) for long agent runs - Apply exponential backoff on
502/503 - Watch cost endpoints in production integrations
10. Security Considerations
10.1 Input Validation
- Enforce max prompt / attachment sizes client-side as well as server-side
- Sanitize filenames on uploads
- Treat model output as untrusted when displaying in HTML (XSS)
10.2 Data Minimization & Sensitive Data
- Send the minimum sensitive data required for the task
- Prefer
externalIdopaque tokens over raw personal identifiers when feasible - Use
noLogonly when the project explicitly allows it — metrics still remain - Follow your organisation's Acceptable Use and retention policies
10.3 Secrets
| Secret | Storage |
|---|---|
| API keys | Secrets manager / env |
| JWT / refresh | HttpOnly secure storage / memory |
Pipedream webhookSecret | Secrets manager (shown once) |
| MCP OAuth client secrets | Server-side only (never in API responses) |
Jwt:SecretKey / Encryption:MasterKey | Environment / K8s Secret — never committed |
10.4 Webhook authenticity
- Verify signatures with the connection’s secret
- Reject unsigned bodies
- Do not distinguish “unknown connection” from “bad signature” in client logs exposed to untrusted parties
10.5 Network
- Production APIs are often internal-only
- Public webhook base URLs (automations) must be HTTPS in production and tightly scoped
- Hosted MCP / agent pods run with restricted Pod Security; do not inject host credentials into workspaces
11. Troubleshooting
11.1 Common Issues
401 Unauthorized
- Missing/invalid
x-api-keyor JWT - Expired API key or access token — refresh or renew
- Webhook: wrong signature or connection id
/api/ai/*called with JWT only — use an API key
403 Forbidden
- API key project mismatch
- Non-admin calling AdminOnly route
- Member trying to edit a development agent (repository-backed)
400 Bad Request
- Missing
prompt/messageUser/ multipartfile - Invalid cron / time zone on scheduled tasks
- KB / MCP ids not visible to the project
409 Conflict
- Duplicate knowledge-base name in project
- Second automation approval
- Unique constraint (idempotency)
502 Bad Gateway
- Upstream model provider outage or quota
- Retry with backoff; fail over
providerId
503 Service Unavailable
- Feature flag off — check
GET /api/features - Internal KB on non-PostgreSQL
- Hosted MCP / agents without Kubernetes
- Automations disabled
Slow responses / stuck sessions
- Check
/api/sessions/{id}/diagnosticsfor pod provisioning - Confirm kubeconfig / cluster capacity
- Review budgets and tool-loop limits
11.2 Debugging Tips
# Capability matrix
curl -s https://localhost:7003/api/features | jq
# Auth modes
curl -s https://localhost:7003/api/auth/options | jq
# Health
curl -s https://localhost:7003/health
# AI smoke (API key)
curl -s -X POST https://localhost:7003/api/ai/query \
-H "x-api-key: $API_KEY" -H 'Content-Type: application/json' \
-d '{"prompt":"ping","projectId":1}'
# Swagger (Development)
open https://localhost:7003/swagger
Correlate failures with Dashboard logs (requestId) and, for agents/sessions, SSE event streams.
11.3 Getting Help
Include: environment (prod/dev/local), endpoint, HTTP status, requestId, project id, feature-flag snapshot (/api/features), redacted request body, and timestamp. Contact your platform administrator or operations team.
Appendices
Appendix A: Complete API Reference (summary)
Auth legend: K = API Key, J = JWT, A = Admin, Anon = AllowAnonymous, D = Delegation, HMAC = webhook signature, T = MCP controller token.
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
| GET | /health | Anon | Liveness |
| GET | /api/features | Anon | Capability flags |
| GET | /api/auth/options | Anon | Login modes |
| POST | /api/auth/login | Anon | Local login |
| GET | /api/auth/google | Anon | Google OAuth start |
| POST | /api/auth/refresh | Anon | Refresh JWT |
| POST | /api/auth/logout | Anon | Revoke refresh |
| POST | /api/auth/apikey | J | Create API key |
| GET | /api/auth/apikey | J | List API keys |
| PUT | /api/auth/changepassword | J | Change password |
| POST | /api/ai/query | K | Text query |
| POST | /api/ai/queryImage | K | Vision |
| POST | /api/ai/queryDocument | K | Document Q&A |
| POST | /api/ai/queryAudio | K | Batch STT |
| WS | /api/ai/realtime/transcribe | K | Live STT |
| POST | /api/ai/chat | K | Chat + MCP/KB |
| POST | /api/ai/vote/{requestId} | K | Feedback |
| POST | /api/ai/vote/chat/{chatId}/{messageIndex} | K | Chat feedback |
| GET | /api/ai/logs | K | Project logs |
| GET | /api/ai/assistants | K | Azure assistants |
| GET | /api/ai/download-blob / /view-blob | K | Blob access |
| GET/POST | /v1/models, /v1/chat/completions, /v1/audio/transcriptions, /v1/embeddings | K | OpenAI compat |
| GET | /api/chat/sessions, /api/chat/conversation/{id} | J/K | Chat history |
| GET | /api/chatadmin/… | A | Admin chat history |
| CRUD | /api/project… | J/A | Projects & members |
| * | /api/projects/{id}/federation/… | A | Federation |
| POST | /api/delegations/exchange | K | Delegation token |
| CRUD | /api/prompt… | J/A | Prompts |
| CRUD | /api/provider… | J/A | Providers |
| CRUD | /api/knowledge-bases… | A | Internal KB admin |
| GET | /api/projects/{id}/knowledge-bases | J | KB picker |
| CRUD | /api/mcp-servers… | J/A | MCP servers |
| * | /api/mcp-catalog… | A | Catalog |
| * | /api/mcp-servers/{id}/definition… | A/J | Definitions & creds |
| * | /api/mcp-instances… | J/D | Managed instances |
| * | /api/mcp-runtime… | A | Runtime profiles |
| * | /api/mcp-runtime-proxy/{id}/mcp/ | T | Data plane |
| * | /api/integrations… | J | User OAuth/PAT |
| CRUD | /api/agents… | J/A | Agents & grants |
| CRUD | /api/agent-environments… | A | Environments |
| * | /api/agent-runs… | A | Headless runs + SSE |
| * | /api/sessions… | J | Interactive sessions + SSE |
| * | /api/scheduled-tasks… | J | Autonomous tasks |
| * | /api/automations… | J | Automations & grants |
| * | /api/automation-events… | J | Event inbox / test |
| * | /api/automation-approvals… | J | Approvals |
| POST | /api/integration-events/{provider}/{connectionId} | HMAC | Webhook gateway |
| * | /api/integrations/pipedream… | J | Pipedream Connect |
| * | /api/integrations/github… | J | GitHub App |
| GET | /api/cost/… | J | Cost analytics |
| GET | /api/dashboard/… | J | Dashboard |
| GET | /api/security/status | A | Security status |
| POST | /api/security/csp-report | Anon | CSP reports |
Appendix B: Rate Limits
Default: no global platform rate limit is guaranteed in every deployment. Automations expose maxEventsPerHour / maxConcurrentRuns per automation. Clients should still implement polite client-side throttling and backoff on 429/503.
Appendix C: SDK Libraries
| Language | Suggestion |
|---|---|
| C# | Official Kroov.Sdk NuGet (v3.0+) — AI, MCP, agents, sessions, automations, Pipedream; see src/Kroov.Sdk/README.md |
| JavaScript/TypeScript | fetch / axios |
| Python | requests / httpx |
| Any OpenAI SDK | Point base URL at {host}/v1 with API key as Bearer |
Appendix D: Changelog
| Version | Date | Changes |
|---|---|---|
| 2.0.1 | Aug 2026 | Restored as the standalone integrator contract (docs/API-INTEGRATION-GUIDE.md and /docs/api/integration-guide) after the docs cleanup |
| 2.0 | Aug 2026 | Full refresh: feature flags; ApiKey-only /api/ai/*; providerId on image/document; OpenAI /v1; Knowledge Bases; MCP definitions/diagnostics/proxy; Agents, presets, environments, runs; interactive sessions; scheduled tasks; automations / Pipedream / approvals / webhooks; GitHub App; federation; security/AD; corrected vote field isThumbsUp; expanded appendix |
| 1.1 | May 2026 | Live realtime transcription WebSocket; optional language / auto-detect for batch and live audio |
| 1.0 | Jan 2026 | Initial API release (AI query/chat + early MCP section) |
Document Classification: Public - Developer Documentation
Prepared by: Kroov platform team
Last Updated: August 2026
API Version: 2.0 (platform surface)
End of API Integration Guide