Skip to content

API reference

KDBL Context Lake (K-Lake) exposes a REST API. The UI and the kdbl-control CLI both use it, so anything you see in the console can be scripted.

Base URL

Everything except the health probes lives under /api:

https://<your-kdbl-host>/api/...

Authentication

All /api/* endpoints require a bearer token. The two accepted token types:

  • Personal access token (PAT) — minted from /api/tokens or the UI. Format: kdblpat_<base64>.
  • OIDC bearer token — issued by your tenant's identity provider.

Send the token in the Authorization header:

Authorization: Bearer kdblpat_...

Unauthenticated endpoints (no token required):

  • GET /healthz — liveness
  • GET /readyz — readiness
  • GET /api/authn/discover?tenant=<slug> — returns OIDC issuer + client ID for a tenant

Conventions

  • All identifiers in path segments are URL-encoded. s3://my-bucket becomes s3%3A%2F%2Fmy-bucket.
  • Request and response bodies are JSON.
  • Timestamps are ISO-8601 UTC.
  • Listing endpoints accept ?limit= and ?after= for cursor pagination. The next cursor is returned in the response body.
  • Errors return a JSON body { "error": "...", "detail": "..." } with an appropriate 4xx or 5xx status.

Endpoints

Health

Method Path Description
GET /healthz Liveness probe. Always returns 200 if the process is up.
GET /readyz Readiness probe. Returns 200 only if dependencies are reachable.

Sources

Method Path Description
GET /api/sources List sources in the calling tenant
POST /api/sources Create a source (see body below)
GET /api/sources/:id Source detail
DELETE /api/sources/:id Remove a source and its indexed files
GET /api/sources/:id/stats File count, bytes, last indexed time
GET /api/sources/:id/health Last successful crawl + last error
GET /api/sources/:id/crawls Recent crawl runs and outcomes
POST /api/sources/:id/crawl Trigger a crawl
GET /api/sources/:id/files Paginated file listing
GET /api/sources/:id/files/:key Single file detail
POST /api/sources/:id/enabled Toggle the enabled flag
POST /api/sources/:id/bulk-ingest Toggle the bulk-ingest fast path
POST /api/sources/:id/meta-caps Set which optional enrichments to gather
POST /api/sources/:id/backfill-meta Enqueue enrichment for previously-indexed files
GET /api/sources/:id/meta-coverage How many files have each enrichment populated
POST /api/sources/:id/subtree Adjust per-source concurrency hints
POST /api/sources/:id/security-trim Set the per-file trim policy ({mode, fail_closed?})
POST /api/sources/:id/multichannel SMB3 multi-channel (smbfs only)
GET /api/sources/:id/content/search Full-text search over extracted content (?q=&limit=)
POST /api/sources/:id/extract Enable/disable content extraction + filters
GET /api/sources/:id/extract/coverage Extraction status rollup
GET /api/sources/:id/extract/progress Live extraction progress
GET /api/sources/:id/crawl-progress Live crawl progress
GET/POST /api/sources/:id/schedules List / add a recurring crawl or backfill
PATCH/DELETE /api/sources/:id/schedules/:sid Update / remove a schedule
POST /api/sources/:id/schedules/:sid/run Run a schedule now

Create source body:

{
  "source_id": "s3://my-bucket",
  "protocol": "s3",
  "config": { "bucket": "my-bucket", "region": "us-east-1" },
  "secret": { "access_key_id": "AKIA...", "secret_access_key": "..." }
}

Set secret to null to use ambient credentials on the worker (S3 IRSA / instance profile, or Azure Entra ID Workload / Managed Identity for azblob).

The config and secret shapes vary per protocol — see Sources for fields per protocol. For example, an Azure Blob source uses "protocol": "azblob", "config": { "account": "...", "container": "..." }, and a tagged secret such as { "auth": "sas", "sas_token": "..." } or { "auth": "account_key", "account_key": "..." }.

Files & downloads (open the original)

K-Lake extracts text and doesn't store the original bytes, so opening a file means re-fetching it from its source on demand. To let a browser open/verify a citation, the API mints short-lived HS256-signed links that the download route resolves (re-checking access for the principal the link was minted for, then streaming the bytes via the extractor — the API never holds source credentials). Every download is audited (tool = files/download).

Method Path Description
GET /api/files/download?t=<token> Stream the original file behind a signed token. No bearer — the signed token is the credential. &dl=1 forces a download (attachment) instead of an inline preview. 401 if the token is invalid/expired; 404 if the principal can no longer see the file.

The links are produced for you on the responses that reference files, so you rarely build the URL yourself:

  • GET /api/sources/:id/content/search — each hit carries a url (an inline preview link to the original), alongside key/seq/snippet/rank.
  • GET /api/sources/:id/files/:key — the file detail carries both preview_url (inline) and download_url (attachment).

All three are omitted when signed downloads aren't configured (KDBL_DOWNLOAD_SIGNING_SECRET / KDBL_API_PUBLIC_URL / KDBL_INTERNAL_FETCH_TOKEN unset), so a client should treat them as optional. Tokens expire after ~15 minutes (KDBL_DOWNLOAD_TTL_SECS).

Access control (per source)

Method Path Description
GET /api/sources/:id/acl List principals and roles
POST /api/sources/:id/acl Grant a principal access
DELETE /api/sources/:id/acl/:principal Revoke a principal

Status

Method Path Description
GET /api/status Tenant queue depth and per-source rollup
GET /api/status?include_cluster=true Cluster-wide rollup (requires cluster admin)

Discover — data estate (tenant admin)

Data-estate analytics. All three require a tenant-admin token; include_cluster=true additionally requires a cluster-admin token. See Discover.

Method Path Description
GET /api/discover/overview Estate totals (files, bytes, sources, last-indexed) + extraction/searchability coverage. ?source_id= to scope, ?include_cluster=true for cross-tenant.
GET /api/discover/breakdown?dimension=<d> Top-N breakdown. dimensionextension|mime|language|size|age|owner|storage_class|source|exposure; optional source_id, metric=files|bytes, limit (max 100).
GET /api/discover/files?source_id=&dimension=&value= Files behind a bucket (keyset-paginated: limit max 1000, after=<cursor>). Drillable dimensions: extension|mime|owner|storage_class|language.

Capacity — storage & query cost

Method Path Description
GET /api/capacity Storage split (base / lexical / hybrid), chunk + embedding counts, retained-vector bytes, and per-mode query latency for the tenant. ?include_cluster=true for cluster-wide (cluster admin).

Entities — the knowledge graph

Every response is access-trimmed to the calling token. See Knowledge graph.

Method Path Description
GET /api/entities Search by name prefix and/or kind; with no filter, the most-mentioned.
GET /api/entities/{id} One entity. visible_document_count is trimmed to the caller; mention_count is the tenant-wide total.
GET /api/entities/{id}/related Asserted relations (degree-capped).
GET /api/entities/{id}/co-occurring Entities appearing in the same documents — a weaker claim than related.
GET /api/entities/{id}/documents Documents mentioning it — the citation path.
GET /api/entities/documents Documents mentioning a set of entities (the intersection question). Merge-aware.
GET /api/entities/by-file What a document is about — the reverse lookup.
GET /api/entities/{id}/merged The entities folded into this one by a previous merge.
POST /api/entities/{id}/merge Fold a duplicate into another entity. Reversible.
POST /api/entities/{id}/unmerge Detach it again.

TLS trust anchors (tenant admin)

Method Path Description
GET /api/ca-certs Installed trust anchors, with subject, issuer and validity parsed from each certificate.
POST /api/ca-certs Install a PEM trust anchor.
DELETE /api/ca-certs/{cert_id} Remove one. Sources stop trusting it on the next configuration refresh.
GET /api/sources/{source_id}/tls A source's trust mode and effective bundle.
POST /api/sources/{source_id}/tls Set the mode: inherit (default), custom (a named subset), or none (platform roots only).

Support — diagnostic packs

The in-band half of a diagnostic pack. These endpoints stay reachable when an expired licence has blocked everything else.

Method Path Description
GET /api/support/preview What a pack would contain at a given level, collecting nothing.
GET /api/support/diagnostics Collect the in-band half. ?level=metadata|operational|full; full needs a cluster-admin token and an explicit acknowledgement.
GET /api/support/runtime-tests Exercise the dependencies and report what actually works — not just what is configured.
GET /api/support/history Who generated packs, when, at what level, and each pack's digest. No copy of the pack itself is kept.

Tokens (self-service)

Method Path Description
GET /api/tokens List the calling user's tokens (metadata only — no secrets)
POST /api/tokens Mint a new PAT. The raw token is returned once.
DELETE /api/tokens/:id Revoke a token

Users (tenant admin)

Method Path Description
GET /api/users List users in the tenant
POST /api/users Create a user (returns an initial PAT, shown once)
GET /api/users/me Current caller
GET /api/users/:id User detail
PATCH /api/users/:id Update email, display name, groups, admin flag
DELETE /api/users/:id Remove a user

Tenants (cluster admin)

Method Path Description
GET /api/tenants List tenants
POST /api/tenants Create a tenant
GET /api/tenants/:slug Tenant detail
PATCH /api/tenants/:slug Update tenant configuration
DELETE /api/tenants/:slug Remove a tenant
GET /api/tenants/:slug/retention Tenant retention override
PATCH /api/tenants/:slug/retention Set tenant retention override
GET /api/tenants/:slug/directory Read non-secret directory-correlation config + has_*_secret flags
PATCH /api/tenants/:slug/directory Merge graph / ldap / principal_mappings config (secrets stay CLI-only)
GET /api/cluster/retention Cluster-wide retention default

MCP

The Model Context Protocol surface. See MCP server and connecting MCP clients.

Method Path Description
GET /.well-known/oauth-protected-resource RFC 9728 Protected Resource Metadata (unauthenticated)
GET /.well-known/oauth-protected-resource/mcp Path-scoped PRM (unauthenticated)
POST /mcp Streamable-HTTP JSON-RPC endpoint (OAuth 2.1 bearer; aud = the resource URI)
GET /api/mcp/audit Query the MCP audit trail (tenant-scoped; ?tool=&principal=&limit=)

When federated sign-in is configured, K-Lake also serves its own OAuth 2.1 authorization server at the MCP origin. Clients discover and use these themselves — you never call them by hand — but they are the endpoints to check when a connection fails. See OAuth and identity providers.

Method Path Description
GET /.well-known/oauth-authorization-server Authorization server metadata (RFC 8414, unauthenticated)
GET /.well-known/openid-configuration OIDC discovery for the same server
GET /.well-known/jwks.json Public keys the access tokens are signed with
POST /register Dynamic client registration (RFC 7591) — how an assistant registers itself
GET /authorize Start sign-in; renders the K-Lake consent screen
GET /oauth/callback Return leg from your IdP
POST /token Exchange the code, and refresh (rotating refresh tokens)

Example: end-to-end

Add a source, trigger a crawl, watch progress:

# Add
curl -X POST -H "Authorization: Bearer $KDBL_TOKEN" \
     -H "Content-Type: application/json" \
     "$KDBL_URL/api/sources" \
     -d '{
       "source_id": "s3://docs-bucket",
       "protocol": "s3",
       "config": { "bucket": "docs-bucket", "region": "us-east-1" },
       "secret": { "access_key_id": "AKIA...", "secret_access_key": "..." }
     }'

# Crawl
curl -X POST -H "Authorization: Bearer $KDBL_TOKEN" \
     "$KDBL_URL/api/sources/s3%3A%2F%2Fdocs-bucket/crawl"

# Watch
curl -H "Authorization: Bearer $KDBL_TOKEN" \
     "$KDBL_URL/api/sources/s3%3A%2F%2Fdocs-bucket/stats"

Rate limits and pagination

There are no hard request rate limits on the API. Be a good citizen — for bulk reads use the listing endpoints with ?limit= and follow the cursor rather than hammering point lookups.