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:
Authentication¶
All /api/* endpoints require a bearer token. The two accepted token types:
- Personal access token (PAT) — minted from
/api/tokensor the UI. Format:kdblpat_<base64>. - OIDC bearer token — issued by your tenant's identity provider.
Send the token in the Authorization header:
Unauthenticated endpoints (no token required):
GET /healthz— livenessGET /readyz— readinessGET /api/authn/discover?tenant=<slug>— returns OIDC issuer + client ID for a tenant
Conventions¶
- All identifiers in path segments are URL-encoded.
s3://my-bucketbecomess3%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 aurl(an inline preview link to the original), alongsidekey/seq/snippet/rank.GET /api/sources/:id/files/:key— the file detail carries bothpreview_url(inline) anddownload_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. dimension ∈ extension|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.