Start here

Getting started

Kortexio sits between your app and your LLM. For OpenAI SDK clients, set baseURL to https://api.kortexio.io/v1. Ollama-compatible clients can keep using /api/chat. The dashboard lets you toggle which snippet to copy.

  1. Create a free account — no credit card required.
  2. In the dashboard, create an App — each app is an isolated integration with its own API key, config, and tools.
  3. Connect your LLM provider under BYOK (OpenAI, Azure OpenAI, Anthropic, Gemini, or your own on-prem endpoint).
  4. Copy the app's API key and send your first request.
first-request.sh
curl -X POST https://api.kortexio.io/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer cmk_live_YOUR_APP_API_KEY" \
  -H "X-Session-Id: onboarding-chat" \
  -d '{
    "model": "gpt-4o-mini",
    "user": "user-42",
    "messages": [{ "role": "user", "content": "Hi, do you remember my name?" }]
  }'

Save the X-Session-Id response header and send it on every follow-up message in the same conversation. Omit it to start a fresh session. You can pass the end-user id as X-User-Id or as user in the JSON body.

Authentication

Kortexio uses two authentication modes depending on the endpoint:

App API key (integration)

Use this for /v1/* and /api/chat from your product backend or client. The key identifies the App — you do not send X-App-Id. Keys use the format cmk_live_... and are scoped per app.

chat-headers
Authorization: Bearer cmk_live_...
X-User-Id: user-42          # required for /api/chat; optional on /v1 if body.user is set
X-Session-Id: thread-9     # optional — reuse for multi-turn

Dashboard JWT (management)

Endpoints under /api/tenants/me/* require a Keycloak JWT from the user dashboard (apps, API keys, BYOK, memory, billing). Obtain it by signing in at https://app.kortexio.io.

dashboard-headers
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

/api/tenants/signup is public (no auth). Manage, rotate, reveal, and revoke keys from your app's dashboard.

See Errors for exact HTTP status codes and JSON error messages when headers or keys are missing.

Troubleshooting

Errors

All API errors return JSON with a single error string. Messages are in English.

POST /api/chat

Errors are evaluated in order — the first failing check wins.

ConditionHTTPerror
No Authorization header or not Bearer401Missing API key.
Unknown, revoked, or malformed API key401Invalid API key.
Missing X-User-Id header401Missing X-App-Id or X-User-Id header.
X-User-Id invalid (empty, >64 chars, or characters other than a–z, A–Z, 0–9, -)400Invalid appId or userId format.
App has no LLM provider configured400Configure an LLM provider for this App before using /api/chat.
Monthly request quota exceeded429Rate limit exceeded for your tier.
Request body too large413Payload too large.

On rate-limit responses, check X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. X-Upgrade-Url points to billing when you need a higher tier.

missing-user-id.json
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Missing X-App-Id or X-User-Id header."
}
invalid-api-key.json
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "Invalid API key."
}

GET /api/tenants/me/*

ConditionHTTPerror
No dashboard JWT401Unauthorized.
JWT valid but account not linked to a tenant403No tenant is linked to this account.
Memory endpoints without X-User-Id or JWT sub403User id is required (OAuth sub or X-User-Id).

API reference

Prefer the OpenAI-compatible surface at /v1/chat/completions, /v1/models, and /v1/embeddings (BYOK proxy — embeddings do not feed Kortexio memory). Ollama clients continue to use /api/chat. Kortexio enriches chat behind the scenes with memory and, when enabled, agentic tool calls. This reference is generated from the live OpenAPI spec and stays in sync with production.

Machine-readable spec: https://api.kortexio.io/openapi/v1.json (bundled copy: /openapi.json)

Chat

POST/api/chat

Chat completion

Ollama-compatible chat endpoint with memory, BYOK, and optional agentic loop. For OpenAI SDK clients use /v1/chat/completions.

App API key

  • X-User-Id (required) — header: Opaque end-user identifier for memory and rate-limit scoping.
  • X-Session-Id — header: Conversation session id. Auto-generated if omitted; returned in the response header.

Tenants

GET/api/tenants/me

Get tenant profile

Read the authenticated tenant profile.

Dashboard JWT

GET/api/tenants/me/impersonation-notices

Impersonation notices

Audit notices when support accessed the tenant account.

Dashboard JWT

GET/api/tenants/me/onboarding

Onboarding status

Activation checklist progress for the tenant.

Dashboard JWT

POST/api/tenants/me/team-invites

Invite teammate

Invite a colleague to the tenant workspace.

Dashboard JWT

POST/api/tenants/signup

Sign up

Create a new tenant account (public, no auth).

Apps

GET/api/tenants/me/apps

List apps

List tenant apps for the authenticated dashboard user.

Dashboard JWT

POST/api/tenants/me/apps

Create app

Create a new integration app for the tenant.

Dashboard JWT

DELETE/api/tenants/me/apps/{id}

Archive app

Archive (soft-delete) a tenant app.

Dashboard JWT

GET/api/tenants/me/apps/{id}/config

Get app config

Read agentic and integration configuration for an app.

Dashboard JWT

PATCH/api/tenants/me/apps/{id}/config

Patch app config

Partially update agentic and integration configuration.

Dashboard JWT

API keys

GET/api/tenants/me/apps/{appId}/api-keys

List API keys

List active API keys for an app.

Dashboard JWT

POST/api/tenants/me/apps/{appId}/api-keys

Create API key

Create a new API key for an app.

Dashboard JWT

DELETE/api/tenants/me/apps/{appId}/api-keys/{keyId}

Revoke API key

Revoke an app API key.

Dashboard JWT

GET/api/tenants/me/apps/{appId}/api-keys/{keyId}/reveal

Reveal API key

Retrieve the full API key value for copying.

Dashboard JWT

BYOK

GET/api/tenants/me/apps/{id}/llm

Get LLM config

Read the current LLM provider configuration (secrets are never returned).

Dashboard JWT

PUT/api/tenants/me/apps/{id}/llm

Update LLM config

Save provider, model, and credentials (validated before persisting).

Dashboard JWT

POST/api/tenants/me/apps/{id}/llm/test

Test LLM connection

Test an LLM provider configuration without saving it.

Dashboard JWT

Memory

GET/api/tenants/me/apps/{id}/memory

Get memory context

Read session memory and notes for a user.

Dashboard JWT

  • sessionId — query
  • query — query
  • X-User-Id — header: End-user identifier (fallback when JWT sub is not used).
POST/api/tenants/me/apps/{id}/memory/notes

Save memory note

Persist a note across sessions for a user.

Dashboard JWT

  • X-User-Id — header: End-user identifier (fallback when JWT sub is not used).
GET/api/tenants/me/apps/{id}/wiki/documents

List global wiki documents

List app-scoped knowledge documents.

Dashboard JWT

  • sourceId — query
  • offset — query
  • limit — query
DELETE/api/tenants/me/apps/{id}/wiki/documents/{documentId}

Delete global wiki document

Remove an app-scoped knowledge document.

Dashboard JWT

PUT/api/tenants/me/apps/{id}/wiki/documents/{documentId}

Upsert global wiki document

Ingest or update an app-scoped knowledge document.

Dashboard JWT

POST/api/tenants/me/apps/{id}/wiki/documents/batch

Batch upsert global wiki

Ingest multiple app-scoped knowledge documents.

Dashboard JWT

POST/api/tenants/me/apps/{id}/wiki/query

Query global wiki

Keyword search over app-scoped knowledge documents.

Dashboard JWT

Billing

GET/api/tenants/me/billing/checkout-config

Checkout config

Order summary for hosted Mollie checkout.

Dashboard JWT

  • plan (required) — query
  • billing — query
POST/api/tenants/me/billing/confirm

Start checkout

Create Mollie hosted checkout session and return redirect URL.

Dashboard JWT

GET/api/tenants/me/invoices

List invoices

List billing invoices for the tenant.

Dashboard JWT

GET/api/tenants/me/invoices/{id}/pdf

Download invoice PDF

Generate or download a PDF for a billing invoice.

Dashboard JWT

POST/api/tenants/me/tier

Change tier

Upgrade or downgrade the tenant plan.

Dashboard JWT

GET/api/tenants/me/usage

Get usage

Monthly usage summary for the tenant.

Dashboard JWT

Meta

GET/health

Health check

Service health and dependency status.

GET/openapi/v1.json

OpenAPI spec

Machine-readable OpenAPI document (live from production).

MCP

GET/api/tenants/me/apps/{id}/integrations

List MCP integrations

List outbound MCP servers for an app (secrets redacted).

Dashboard JWT

PUT/api/tenants/me/apps/{id}/integrations

Replace MCP integrations

Replace the outbound MCP server list for an app.

Dashboard JWT

POST/api/tenants/me/apps/{id}/integrations/test

Test MCP integration

Probe an MCP server with initialize + tools/list.

Dashboard JWT

POST/api/tenants/me/apps/{id}/mcp/test

Test hosted memory MCP

Probe this app's hosted MCP endpoint with the caller's access token.

Dashboard JWT

OpenAI

POST/v1/chat/completions

Chat completions

OpenAI-compatible chat completions with Kortexio memory, BYOK, and optional agentic loop. Provide X-User-Id or body.user.

App API key

  • X-User-Id — header: Opaque end-user identifier. Optional when body.user is set.
  • X-Session-Id — header: Conversation session id. Auto-generated if omitted; returned in the response header.
POST/v1/embeddings

Create embeddings

OpenAI-compatible embeddings proxy to the App BYOK provider. Does not use Kortexio memory.

App API key

GET/v1/models

List models

Lists the BYOK model configured for this App (OpenAI-compatible).

App API key

GET/v1/models/{id}

Retrieve model

Returns the configured BYOK model when id matches.

App API key

Every public endpoint has a copy-paste curl example in API examples.

The response format is unchanged, with optional extensions under a dedicated field:

response.json
{
  "model": "gpt-4o-mini",
  "message": { "role": "assistant", "content": "..." },
  "done": true,
  "kortexio": {
    "message_id": "...",
    "agentic": {
      "phase": "completed",
      "awaiting_confirmation": false
    }
  }
}

Set "stream": true for server-sent events. Tool calls and internal reasoning never leak into the stream — only the final answer is emitted.

Copy & paste

API examples

One curl example per public endpoint. Replace placeholders: cmk_live_YOUR_APP_API_KEY, YOUR_DASHBOARD_JWT, and app/key GUIDs from your dashboard.

Chat

POST/api/chatApp API key

Chat completion (Ollama)

Ollama-compatible chat with automatic memory injection, BYOK routing, and optional agentic loop. Prefer /v1/chat/completions for OpenAI SDK clients. The App is resolved from your API key — do not send X-App-Id.

Headers

  • Authorization (required)Bearer cmk_live_... (App API key)
  • X-User-Id (required)Opaque end-user id from your product (email hash, internal id, etc.)
  • X-Session-IdConversation session id; auto-generated if omitted and returned in the response header
  • Content-Type (required)application/json

Request body

request.json
{
  "model": "gpt-4o-mini",
  "messages": [
    { "role": "user", "content": "My favourite colour is blue." }
  ]
}

Example

curl
curl -X POST https://api.kortexio.io/api/chat \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer cmk_live_YOUR_APP_API_KEY" \
  -H "X-User-Id: user-42" \
  -H "X-Session-Id: support-thread-9" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{ "role": "user", "content": "Hi!" }]
  }'

Response

response.json
{
  "model": "gpt-4o-mini",
  "message": { "role": "assistant", "content": "Got it — I'll remember that." },
  "done": true,
  "context_memory": {
    "message_id": "..."
  }
}
  • Memory is scoped by (App, X-User-Id, X-Session-Id). Reuse the same session id for multi-turn context.
  • Omit X-Session-Id to start a fresh conversation for the same user — Turn 1 memory is not recalled (new session id in response headers).
  • Set "stream": true for NDJSON streaming (application/x-ndjson).
  • Errors (English JSON): 401 Missing API key. | 401 Invalid API key. | 401 Missing X-App-Id or X-User-Id header. | 400 Invalid appId or userId format. | 400 Configure an LLM provider for this App before using /api/chat. | 429 Rate limit exceeded for your tier.
  • See https://kortexio.io/docs#errors for the full error table.

Tenants

POST/api/tenants/signupNo auth

Sign up

Create a new tenant account. Public — no authentication required.

Request body

request.json
{
  "name": "Acme Corp",
  "email": "ops@acme.example",
  "password": "choose-a-strong-password"
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/signup \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "email": "ops@acme.example",
    "password": "choose-a-strong-password"
  }'

Response

response.json (201)
{
  "tenantId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "email": "ops@acme.example"
}
  • Prefer the web signup flow at /signup for Keycloak account provisioning.
GET/api/tenants/meDashboard JWT

Get tenant profile

Read the authenticated tenant profile, plan limits, and suspension status.

Example

curl
curl -s https://api.kortexio.io/api/tenants/me \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "name": "Acme Corp",
  "tier": "Free",
  "maxApps": 2,
  "monthlyRequestLimit": 1000,
  "hasPaymentMethod": false,
  "suspendedAt": null
}
GET/api/tenants/me/impersonation-noticesDashboard JWT

Impersonation notices

Audit trail entries when Kortexio support accessed your tenant account.

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/impersonation-notices \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
[
  {
    "occurredAt": "2026-07-01T14:22:00Z",
    "reason": "Billing investigation ticket #4821"
  }
]

Apps

GET/api/tenants/me/appsDashboard JWT

List apps

List all active integration apps for the tenant.

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/apps \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
[
  {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Production",
    "gatewayAppId": "acme-prod-7f3a",
    "createdAt": "2026-06-15T10:00:00Z"
  }
]
POST/api/tenants/me/appsDashboard JWT

Create app

Create a new isolated integration app (own API keys, LLM config, memory, and agentic settings).

Request body

request.json
{ "name": "Staging" }

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{ "name": "Staging" }'

Response

response.json (201)
{
  "id": "00000000-0000-0000-0000-000000000001",
  "name": "Staging",
  "gatewayAppId": "acme-staging-a1b2",
  "createdAt": "2026-07-09T12:00:00Z"
}
  • Returns 403 when the tenant has reached the max apps limit for their plan.
DELETE/api/tenants/me/apps/{id}Dashboard JWT

Archive app

Soft-delete (archive) an app. Archived apps stop accepting chat requests.

Path parameters

  • idApp GUID

Example

curl
curl -X DELETE https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001 \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"
  • Returns 204 No Content on success.
GET/api/tenants/me/apps/{id}/configDashboard JWT

Get app config

Read agentic tools, guardrails, persona, web search, and integration settings for an app.

Path parameters

  • idApp GUID

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/config \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json (excerpt)
{
  "agentic": {
    "enabled": false,
    "guardrails": { "maxIterations": 10 }
  },
  "webSearch": { "enabled": false }
}
PATCH/api/tenants/me/apps/{id}/configDashboard JWT

Patch app config

Partially update app configuration. Tier gating may reject Enterprise-only features on lower plans.

Path parameters

  • idApp GUID

Request body

request.json
{
  "agentic": {
    "enabled": true,
    "guardrails": { "maxIterations": 8 }
  }
}

Example

curl
curl -X PATCH https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/config \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{
    "agentic": { "enabled": true }
  }'

API keys

POST/api/tenants/me/apps/{appId}/api-keysDashboard JWT

Create API key

Issue a new App API key. The full key is only returned once at creation — store it securely.

Path parameters

  • appIdApp GUID

Request body

request.json
{ "name": "CI deploy key" }

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{ "name": "CI deploy key" }'

Response

response.json (201)
{
  "id": "00000000-0000-0000-0000-000000000002",
  "apiKey": "cmk_live_YOUR_APP_API_KEY",
  "prefix": "cmk_live_d1cda418",
  "createdAt": "2026-07-09T12:00:00Z"
}
  • Key format: cmk_live_{32-hex-chars}. Use GET .../reveal to copy an existing key later.
GET/api/tenants/me/apps/{appId}/api-keysDashboard JWT

List API keys

List API keys for an app (prefix and metadata only — never the full secret).

Path parameters

  • appIdApp GUID

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/api-keys \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
[
  {
    "id": "00000000-0000-0000-0000-000000000002",
    "prefix": "cmk_live_d1cda418",
    "name": "CI deploy key",
    "createdAt": "2026-07-09T12:00:00Z",
    "lastUsedAt": "2026-07-09T18:30:00Z",
    "revokedAt": null
  }
]
GET/api/tenants/me/apps/{appId}/api-keys/{keyId}/revealDashboard JWT

Reveal API key

Retrieve the full API key value for copying (dashboard JWT required).

Path parameters

  • appIdApp GUID
  • keyIdAPI key GUID

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/api-keys/00000000-0000-0000-0000-000000000002/reveal \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
{ "apiKey": "cmk_live_YOUR_APP_API_KEY" }
  • Returns 400 if the key was revoked or never stored for reveal.
DELETE/api/tenants/me/apps/{appId}/api-keys/{keyId}Dashboard JWT

Revoke API key

Revoke an API key immediately. In-flight requests may fail with 401.

Path parameters

  • appIdApp GUID
  • keyIdAPI key GUID

Example

curl
curl -X DELETE https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/api-keys/00000000-0000-0000-0000-000000000002 \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"
  • Returns 204 No Content on success.

BYOK

GET/api/tenants/me/apps/{id}/llmDashboard JWT

Get LLM config

Read the current LLM provider configuration. API keys are never returned.

Path parameters

  • idApp GUID

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/llm \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
{
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "baseUrl": "https://api.anthropic.com/v1",
  "apiKeyConfigured": true
}
PUT/api/tenants/me/apps/{id}/llmDashboard JWT

Update LLM config

Save provider, model, base URL, and API key. Credentials are validated before persisting.

Path parameters

  • idApp GUID

Request body

request.json
{
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "baseUrl": null,
  "apiKey": "sk-ant-..."
}

Example

curl
curl -X PUT https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/llm \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{
    "provider": "openai",
    "model": "gpt-4o-mini",
    "baseUrl": null,
    "apiKey": "sk-..."
  }'

Response

response.json
{
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "baseUrl": "https://api.anthropic.com/v1",
  "apiKeyConfigured": true
}
  • Supported providers: openai, azure-openai, anthropic, gemini, onprem.
  • Omit apiKey to keep the existing secret unchanged.
POST/api/tenants/me/apps/{id}/llm/testDashboard JWT

Test LLM connection

Test a provider configuration without saving it to the database.

Path parameters

  • idApp GUID

Request body

request.json
{
  "provider": "anthropic",
  "model": "claude-sonnet-4-6",
  "baseUrl": null,
  "apiKey": "sk-ant-..."
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/llm/test \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{
    "provider": "anthropic",
    "model": "claude-sonnet-4-6",
    "apiKey": "sk-ant-..."
  }'

Response

response.json
{ "success": true, "message": "Connection OK." }

Memory

GET/api/tenants/me/apps/{id}/memoryDashboard JWT

Get memory context

Read the session wiki, recent summary, and resolved session id for an end user.

Path parameters

  • idApp GUID

Headers

  • X-User-IdEnd-user id when not using the JWT sub claim (typical for server-to-server reads)

Query parameters

  • sessionIdSession to read; defaults to a new session if omitted
  • queryOptional semantic search within session memory

Example

curl
curl -s "https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/memory?sessionId=support-thread-9" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -H "X-User-Id: user-42"

Response

response.json
{
  "wikiMarkdown": "# Session notes\n- Favourite colour: blue",
  "recentSummary": "User prefers blue.",
  "sessionId": "a1b2c3d4e5f6..."
}
  • Requires X-User-Id header or an authenticated JWT with a sub claim.
POST/api/tenants/me/apps/{id}/memory/notesDashboard JWT

Save memory note

Persist a note into the user's cross-session memory (injected into future chat context).

Path parameters

  • idApp GUID

Headers

  • X-User-IdEnd-user id when not using the JWT sub claim

Request body

request.json
{
  "sessionId": "support-thread-9",
  "note": "Customer prefers email contact after 5pm."
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/memory/notes \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -H "X-User-Id: user-42" \
  -d '{
    "sessionId": "support-thread-9",
    "note": "Customer prefers email contact after 5pm."
  }'

Response

response.json
{ "saved": true, "sessionId": "support-thread-9" }

Global Wiki

PUT/api/tenants/me/apps/{id}/wiki/documents/{documentId}Dashboard JWT

Upsert global wiki document

Ingest or update an app-scoped knowledge document. Stable documentId enables idempotent upserts (unchanged content hash skips a rewrite).

Path parameters

  • idApp GUID
  • documentIdStable id (e.g. jira:PROJ-123, confluence:12345)

Request body

request.json
{
  "title": "PROJ-123 — Fix renewal invoice",
  "content": "# PROJ-123\n\n## Description\nCustomers see wrong renewals.",
  "summary": "Billing renewal invoice bug",
  "sourceId": "jira:PROJ",
  "metadata": { "project": "PROJ", "issueType": "Bug" }
}

Example

curl
curl -X PUT https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/documents/jira%3APROJ-123 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{
    "title": "PROJ-123 — Fix renewal invoice",
    "content": "# PROJ-123\n\n## Description\nCustomers see wrong renewals.",
    "sourceId": "jira:PROJ"
  }'

Response

response.json
{
  "appId": "demo-prod-abc123",
  "documentId": "jira:PROJ-123",
  "slug": "jira-proj-123",
  "contentHash": "a1b2c3...",
  "updatedAt": "2026-07-23T00:00:00Z",
  "created": true,
  "unchanged": false
}
  • Documents are shared across all sessions of this app.
  • Enable Global Wiki for the app in the dashboard so chat can call wiki_search.
POST/api/tenants/me/apps/{id}/wiki/documents/batchDashboard JWT

Batch upsert global wiki documents

Ingest multiple app-scoped knowledge documents in one request.

Path parameters

  • idApp GUID

Request body

request.json
{
  "documents": [
    {
      "documentId": "jira:PROJ-123",
      "content": "# PROJ-123\n...",
      "sourceId": "jira:PROJ"
    },
    {
      "documentId": "confluence:98765",
      "content": "# Billing FAQ\n...",
      "sourceId": "confluence:DOCS"
    }
  ]
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/documents/batch \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{"documents":[{"documentId":"jira:PROJ-123","content":"# PROJ-123\n...","sourceId":"jira:PROJ"}]}'
GET/api/tenants/me/apps/{id}/wiki/documentsDashboard JWT

List global wiki documents

Paginated list of app knowledge documents, optionally filtered by sourceId.

Path parameters

  • idApp GUID

Query parameters

  • sourceIdFilter by source (e.g. jira:PROJ)
  • offsetPagination offset (default 0)
  • limitPage size (default 50, max 200)

Example

curl
curl -s "https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/documents?sourceId=jira%3APROJ&limit=20" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"
DELETE/api/tenants/me/apps/{id}/wiki/documents/{documentId}Dashboard JWT

Delete global wiki document

Remove an app-scoped knowledge document by documentId.

Path parameters

  • idApp GUID
  • documentIdStable document id

Example

curl
curl -X DELETE https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/documents/jira%3APROJ-123 \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"
POST/api/tenants/me/apps/{id}/wiki/queryDashboard JWT

Query global wiki

Keyword search over ingested documents. Returns compiled Markdown plus scored matches — used by agentic wiki_search and by backends that need retrieval without chat.

Path parameters

  • idApp GUID

Request body

request.json
{
  "query": "subscription renewal invoice",
  "sourceId": "jira:PROJ",
  "topK": 5,
  "budgetChars": 8000,
  "includeIndex": false,
  "asOf": "2026-03-01T00:00:00Z"
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{"query":"subscription renewal invoice","topK":5,"asOf":"2026-03-01T00:00:00Z"}'

Response

response.json
{
  "compiledMarkdown": "## jira-proj-123\n# PROJ-123\n...",
  "charCount": 1200,
  "includedDocuments": 2,
  "totalDocuments": 40,
  "truncated": false,
  "asOf": "2026-03-01T00:00:00Z",
  "matches": [
    { "documentId": "jira:PROJ-123", "slug": "jira-proj-123", "title": "PROJ-123", "score": 28.5, "sourceId": "jira:PROJ", "revisionId": "…" }
  ]
}
POST/api/tenants/me/apps/{id}/wiki/digests/rebuildDashboard JWT

Rebuild digests and wiki:catalog

Generates LLM digests (Keywords + short bullets) for ingested documents and refreshes the synthetic wiki:catalog document. Use after bulk ingest; force regenerates every digest.

Path parameters

  • idApp GUID

Request body

request.json
{
  "force": false,
  "sourceId": "jira:PROJ"
}

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/apps/00000000-0000-0000-0000-000000000001/wiki/digests/rebuild \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{"force":false}'

Response

response.json
{
  "appId": "demo-app",
  "processed": 40,
  "updated": 12,
  "skipped": 28,
  "catalogRefreshed": true
}

Billing

GET/api/tenants/me/usageDashboard JWT

Get usage

Monthly request and token usage summary for the tenant.

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/usage \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
{
  "periodYearMonth": "2026-07",
  "requestsUsed": 842,
  "tokensUsed": 125000,
  "requestLimit": 1000,
  "remaining": 158,
  "resetUnixSeconds": 1754006400
}
POST/api/tenants/me/tierDashboard JWT

Change tier

Upgrade or downgrade the tenant plan. Paid upgrades may return a Mollie checkout URL.

Request body

request.json
{ "tier": "Base" }

Example

curl
curl -X POST https://api.kortexio.io/api/tenants/me/tier \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -d '{ "tier": "Base" }'

Response

response.json
{
  "tier": "Base",
  "checkoutUrl": "https://www.mollie.com/checkout/...",
  "message": "Complete payment to activate Base."
}
  • Valid tiers: Free, Base, Enterprise.
GET/api/tenants/me/invoicesDashboard JWT

List invoices

List billing invoices and payment status for the tenant.

Example

curl
curl -s https://api.kortexio.io/api/tenants/me/invoices \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT"

Response

response.json
[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "type": "subscription",
    "periodYearMonth": "2026-07",
    "amountCents": 2900,
    "currency": "EUR",
    "status": "paid",
    "description": "Base plan — July 2026",
    "createdAt": "2026-07-01T00:00:00Z",
    "paidAt": "2026-07-01T00:05:00Z"
  }
]

Meta

GET/healthNo auth

Health check

Returns service health and dependency status (PostgreSQL, Redis).

Example

curl
curl -s https://api.kortexio.io/health

Response

response.json
{
  "status": "healthy",
  "checks": {
    "postgres": "ok",
    "redis": "ok"
  }
}
GET/openapi/v1.jsonNo auth

OpenAPI spec

Machine-readable OpenAPI 3 document for all public endpoints (live from production).

Example

curl
curl -s https://api.kortexio.io/openapi/v1.json | jq .info
  • Bundled copy for offline reference: /openapi.json on this docs site.

Bring your own key

BYOK

Every App connects to the LLM provider of your choice. Kortexio never sees or stores your prompts anywhere except your own configured backend.

Supported providers:

  • OpenAI
  • Azure OpenAI
  • Anthropic
  • Google Gemini
  • On-prem / self-hosted (Ollama, LM Studio, any OpenAI-compatible endpoint)

Configure providers from the dashboard or via the BYOK endpoints in the API reference. /api/chat returns an error until an App has a working LLM connection configured.

Memory

Memory is scoped by three identifiers. Your integration only sets two of them — Kortexio resolves the App from the API key automatically:

  • App — from Authorization: Bearer cmk_live_...
  • User — from X-User-Id (required on chat)
  • Session — from X-Session-Id (optional; auto-generated if omitted)

Isolation key: (App, User, Session). Two users on the same app never share memory. Two sessions for the same user are independent unless you reuse the same X-Session-Id.

Each session keeps a compact wiki (Markdown summary + recent history) injected into every chat request. You only send the newest message — Kortexio builds the full context. For facts that should be shared across every session of an app (product docs, Jira, Confluence), use Global Wiki.

multi-turn.sh
# Turn 1 — start a session (save X-Session-Id from response headers)
curl -D - -X POST https://api.kortexio.io/api/chat \
  -H "Authorization: Bearer cmk_live_..." \
  -H "X-User-Id: user-42" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Remember: KORTEX-PINEAPPLE"}]}'

# Turn 2 — same user, same session (memory is recalled)
curl -X POST https://api.kortexio.io/api/chat \
  -H "Authorization: Bearer cmk_live_..." \
  -H "X-User-Id: user-42" \
  -H "X-Session-Id: SESSION_ID_FROM_TURN_1" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"What was the secret word?"}]}'
# → KORTEX-PINEAPPLE

# Turn 3 — same user, new session (omit X-Session-Id)
curl -X POST https://api.kortexio.io/api/chat \
  -H "Authorization: Bearer cmk_live_..." \
  -H "X-User-Id: user-42" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"What was the secret word from earlier?"}]}'
# → model has no memory of Turn 1 — new X-Session-Id in response headers

Turn 3 is the same X-User-Id with a fresh session. Memory from Turn 1 is not injected — only reusing X-Session-Id keeps multi-turn context.

Use the Memory endpoints in the API examples to read session wikis or persist cross-session notes from your backend.

Knowledge base

Global Wiki

Global Wiki is an app-scoped knowledge base — Markdown documents ingested from Jira, Confluence, SQL exports, files, or your own pipelines. Unlike session memory, these documents are shared by every user and session under the same app.

  • Ingest — upsert documents with a stable documentId (idempotent by content hash). Batch ingest is supported.
  • Temporal knowledge — revisioned facts with supersede history and point-in-time asOf queries, so audits and “what changed?” answers stay honest.
  • Digests & catalog — LLM digests after bulk ingest plus a wiki:catalog so large corpora stay discoverable without stuffing the prompt.
  • Query — keyword search returns a compact Markdown snippet with the best matches (budget-capped for token economy).
  • Chat — when Global Wiki is enabled for the app, the model can call wiki_search only when it needs documented facts — greetings and pure session chat stay cheap.
  • Dashboard — configure per app under Apps → Global Wiki.
ingest-and-query.sh
# Upsert a document (dashboard JWT) — content changes supersede by default
curl -X PUT https://api.kortexio.io/api/tenants/me/apps/YOUR_APP_ID/wiki/documents/jira:PROJ-123 \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "PROJ-123 — Fix renewal invoice",
    "content": "# PROJ-123\n\n## Description\n...",
    "sourceId": "jira:PROJ",
    "summary": "Billing renewal invoice bug"
  }'

# After bulk ingest — rebuild digests + wiki:catalog
curl -X POST https://api.kortexio.io/api/tenants/me/apps/YOUR_APP_ID/wiki/digests/rebuild \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -H "Content-Type: application/json" \
  -d '{"force": false}'

# Search now — or asOf for a point in time
curl -X POST https://api.kortexio.io/api/tenants/me/apps/YOUR_APP_ID/wiki/query \
  -H "Authorization: Bearer YOUR_DASHBOARD_JWT" \
  -H "Content-Type: application/json" \
  -d '{"query":"subscription renewal invoice","topK":5,"asOf":"2026-03-01T00:00:00Z"}'

Manage ingest, digests, and point-in-time query from the dashboard under Apps → Global Wiki. Full shapes are in the API examples. Hosted MCP exposes wiki_search (with optional asOf) and upsert_wiki_document. Try tools and HITL in Apps → Playground.

Agentic tools

Turn on the agentic loop for an app and Kortexio can call tools mid-conversation — still on the same /api/chat endpoint, with no new integration surface for your app.

  • Skills & guardrails — platform and per-app policy packs (Markdown) steer behaviour: anti-hallucination, wiki-first, privacy, and your own packs. Max iterations, timeouts, egress policy, and confirmation keywords stay configurable.
  • Human-in-the-loop — destructive actions pause and wait for explicit confirmation before running. Streaming responses can include context_memory.agentic progress so clients show iteration/tool timelines.
  • Playground — exercise memory, tools, and HITL from Apps → Playground with streaming and an agentic timeline before you wire production.
  • Global Wiki — when enabled, wiki_search is available as a built-in tool (see Global Wiki).
  • Integration tools — call external MCP servers as tools (available on all paid plans).
  • Native code execution (shell / Python / Node, sandboxed) — available on the Enterprise plan.

When a confirmation is required, the response includes a confirmation token; replying with it (or natural language like "confirm") resumes execution. Every step is logged for audit.

MCP

Kortexio speaks MCP (Model Context Protocol) in both directions:

  • As a client — your agentic tool config can point at any MCP server (internal tools, Zuora, Jira, etc.) and Kortexio calls it during the loop. Configure outbound servers in the dashboard under Apps → MCP (Base+).
  • As a server — each App exposes hosted memory at https://mcp.kortexio.io/{appId}/mcp. Cursor and other MCP clients authenticate via OAuth (Keycloak) using the public client mcp-server. Hosted tools include get_memory_context, save_memory_note, wiki_search, and upsert_wiki_document.

Try the Demo App

Use the public Kortexio Demo app to connect without creating your own App ID first. Sign in with any Kortexio account when Cursor prompts for OAuth — memory is scoped per user.

Demo App ID: 46c6f0dd-57d0-486c-a2a1-c8b143dec78b
Demo MCP URL: https://mcp.kortexio.io/46c6f0dd-57d0-486c-a2a1-c8b143dec78b/mcp

{
  "mcpServers": {
    "kortexio-memory": {
      "url": "https://mcp.kortexio.io/46c6f0dd-57d0-486c-a2a1-c8b143dec78b/mcp",
      "auth": {
        "CLIENT_ID": "mcp-server",
        "scopes": ["openid", "profile"]
      }
    }
  }
}

Find us in MCP directories

Connect Cursor to your own app

Open Apps → your app → MCP for the ready-made snippet with your real App ID. Or add this to Cursor mcp.json:

{
  "mcpServers": {
    "kortexio-memory": {
      "url": "https://mcp.kortexio.io/YOUR_APP_ID/mcp",
      "auth": {
        "CLIENT_ID": "mcp-server",
        "scopes": ["openid", "profile"]
      }
    }
  }
}

OAuth discovery uses Protected Resource Metadata at https://mcp.kortexio.io/.well-known/oauth-protected-resource. Health: https://mcp.kortexio.io/health.

Hosted tools: get_memory_context, save_memory_note.

Apps & multi-tenant

An App is an isolated integration: its own API key, LLM connection, agentic config, and guardrails. Most customers create one app per product or environment (e.g. staging vs. production).

Manage apps and API keys via the dashboard or the Apps / API keys sections in the API reference.

Plans & limits

Concrete limits by tier: Free (1,000 req/mo), Base (50,000), Team (400,000), Enterprise (custom). See pricing for full comparison including web search, MCP servers, and memory retention. Native code execution (shell/Python/Node) is Enterprise only; MCP integrations and BYOK are available on paid tiers.

Changelog & status

  • Global Wiki — app-scoped knowledge base with ingest/query APIs, dashboard toggle, built-in wiki_search, and MCP tools wiki_search / upsert_wiki_document. See Global Wiki.

Full release notes and uptime status are being set up. Reach out at hello@kortexio.io for incident history or earlier releases.