Skip to content

API reference

KubeManta's agent is a REST API, and everything the dashboard does it does through that API. Anything you can do in the UI you can script — subject to the limits below, which exist so that a leaked key cannot become a cluster takeover.

The schema is served by the product

The agent publishes its own OpenAPI schema, so the authoritative endpoint list is the one running in your cluster rather than a page that can drift from it:

Path What it is
/api/agent/openapi.json OpenAPI 3 schema — every route, parameter and response model
/api/agent/docs Swagger UI — browse and try requests interactively

Both require authentication, like every other route. In a browser you are already signed in, so https://<your-host>/api/agent/docs just works. From a script:

curl -s https://kubemanta.example.com/api/agent/openapi.json \
  -H "X-API-Key: $KM_API_KEY" | jq '.paths | keys[]'

Generate a client

The schema is ordinary OpenAPI 3, so openapi-generator, oapi-codegen and friends will produce a typed client from it directly.


Authentication

Two credential kinds reach the API, and they are not equivalent.

Session cookie (km_session) — what the dashboard uses. HMAC-signed, sliding idle expiry, absolute 7-day ceiling. Not intended for scripts.

Per-user API key (X-API-Key) — what automation uses.

curl -s https://kubemanta.example.com/api/agent/namespaces \
  -H "X-API-Key: km_a1b2c3d4_…"

Keys look like km_<prefix>_<secret>. Only a SHA-256 hash is stored, so the secret is shown once at creation and cannot be recovered — reissue rather than hunt for it.

Creating a key

  • For yourself: the account menu → API keys, or POST /me/api-keys.
  • For another user (admin): Admin → Users → pick the user → API keys → Create.

A key belongs to a user, and that is the point: it carries its owner's role, and the role is re-read from the database on every request. Demote the owner to viewer and the key immediately acts as a viewer; deactivate them, revoke the key, or let it expire and the next call gets a 401. There is no shared secret and nothing to redeploy.

The old shared key is gone

security.apiKey was removed. It was unattributable — every caller looked like the same root principal — could not be revoked without a redeploy, and bypassed the seat model. If you are following an older guide that sets it, that value does nothing.

Attribution

Key requests are audited as <username>@<ip>, so a shared key is visible as one account calling from many addresses. That is deliberate: it makes credential sharing a thing you can see in Activity rather than a thing you have to trust people about.


What an API key cannot do

A key is not a full stand-in for its owner. Identity, billing and escalation surfaces refuse keys outright — even when the owner is an admin — and answer 403 {"error": "api_key_forbidden"}.

Refused Why
/admin/users*, /admin/api-keys*, /me/api-keys* A key must never mint or revoke keys, or change who is an admin
/admin/sso*, /admin/sessions*, /admin/license* Identity and licensing are not scriptable with a key
/settings/ai A GET returns your LLM provider key unmasked
/admin/ai-guardrails, /admin/access-control (writes) The AI kill switch, redaction, and IP bans. Reads are allowed
/admin/*, /settings/* (writes) Includes expert mode — the toggle that enables cluster-admin delegation
/kubemanta/db/* The purge would erase the record of the key's own use
/helm/configs, /builder/bundles (reads) These decrypt before returning; a saved config can hold credentials
/terminal/* and the terminal WebSocket Refused by credential kind, whatever the owner's role

The reasoning is one scenario: a leaked key should not be able to enable expert mode, apply a manifest as cluster-admin, disable redaction, ban the operators, and then purge the audit trail — each step is individually plausible, and together they are a takeover that needs no browser and no shell.

Everything not listed is reachable and inherits the owner's role. That default-allow shape is why the list is enforced as prefix rules rather than an enumeration: a route added tomorrow under /admin/ is refused the day it lands, not the day somebody remembers to add it.


Base path

Through the UI (the normal case), every agent route is under /api/agent:

https://<your-host>/api/agent/<route>

Talking to the agent Service directly inside the cluster, drop that prefix:

http://kubemanta-agent.kubemanta-system.svc:8080/<route>

Worked examples

export KM=https://kubemanta.example.com/api/agent
export KM_API_KEY=km_a1b2c3d4_…

# Namespaces you can see
curl -s "$KM/namespaces" -H "X-API-Key: $KM_API_KEY" | jq '.namespaces[].name'

# Pods in one namespace
curl -s "$KM/namespaces/prod/pods" -H "X-API-Key: $KM_API_KEY" | jq '.pods[].name'

# Current security posture (grade, severity counts, coverage)
curl -s "$KM/security/posture?namespace=prod" -H "X-API-Key: $KM_API_KEY" \
  | jq '{grade, score, by_severity, workloads_covered}'

# Findings, newest scan, worst first — paginated
curl -s "$KM/security/findings?page=1&page_size=50&sort=severity" \
  -H "X-API-Key: $KM_API_KEY" | jq '.total, .rows[0]'

# Export the current findings as CSV
curl -s "$KM/security/findings/export?format=csv" -H "X-API-Key: $KM_API_KEY" > findings.csv

Rate limits and errors

Status Meaning
401 No credential, an expired session, or a revoked/expired key
402 The endpoint needs a license tier you do not have — the body carries feature and an upgrade hint
403 Authenticated but not permitted: a viewer calling a write, a denied IP, or api_key_forbidden
429 Login lockout, or the discovery rate limit
503 The agent is shedding load (in-flight cap) — retry with the Retry-After header

Errors are JSON objects with an error field where the distinction matters programmatically, so branch on that rather than parsing prose.


See also