Skip to content

API Reference

Complete REST API documentation for the Kure Monitor backend.

Base URL: http://<backend-host>:8000/api

Two distinct mechanisms (since 2.3.0):

  • User sessions (cookie-based) for dashboard / browser traffic
  • Service token (X-Service-Token header) for agent and scanner traffic

The legacy AUTH_API_KEY / auth.apiKey single-key model was removed in 2.3.0.

Log in with POST /api/auth/login (username + password). On success the backend sets an HttpOnly cookie named kure_session, signed with SESSION_SECRET. All subsequent /api/* calls from the browser use that cookie automatically.

Rate limit: 5 login attempts per 30 seconds.

Ingest endpoints authenticate with the X-Service-Token HTTP header:

X-Service-Token: <SERVICE_TOKEN value>

WebSocket and SSE log streams use a query parameter instead:

ws://localhost:8000/api/ws?token=YOUR_SERVICE_TOKEN
GET /api/pods/{namespace}/{pod_name}/logs/stream?token=YOUR_SERVICE_TOKEN
EndpointPurpose
GET /health, GET /metricsLiveness / Prometheus scrape
GET /api/auth/statusWhether initial admin setup is needed
POST /api/auth/loginLog in with username + password
POST /api/auth/signupCreate the initial admin (only when no users exist)
EndpointCaller
POST /api/pods/failedAgent
POST /api/pods/dismiss-deletedAgent
POST /api/security/findingsScanner
POST /api/security/scan/clearScanner
POST /api/security/rescan-statusScanner
DELETE /api/security/findings/resource/{type}/{ns}/{name}Scanner
POST /api/metrics/security-scan-durationScanner
401 Unauthorized
{
"detail": "Not authenticated"
}
CategoryEndpointDescription
ConfigGET /configApp status
PodsPOST /pods/failedReport failure
PodsGET /pods/failedList active failures
PodsGET /pods/historyList resolved pods
PodsGET /pods/ignoredList ignored pods
PodsPUT /pods/{id}/statusUpdate status
PodsDELETE /pods/failed/{id}Dismiss
PodsPOST /pods/failed/{id}/retry-solutionRegenerate AI solution
PodsGET /pods/{ns}/{name}/logsGet logs
SecurityPOST /security/findingsReport finding
SecurityGET /security/findingsList findings
SecurityPOST /security/findings/{id}/fixGenerate AI fix
SecurityGET / POST / DELETE /security/trusted-registriesManage trusted registries
MirrorPOST /mirror/preview/{id}Generate fixed manifest
MirrorPOST /mirror/deploy/{id}Deploy mirror pod
MirrorGET /mirror/status/{id}Mirror status
MirrorDELETE /mirror/{id}Delete mirror
MirrorGET /mirror/activeList active mirrors
DiagramGET /diagram/namespacesList namespaces
DiagramGET /diagram/namespace/{ns}Per-namespace graph
DiagramGET /diagram/workload/{ns}/{kind}/{name}Per-workload graph
DiagramGET /diagram/manifest/{ns}/{kind}/{name}Live manifest (rejects Secret with 403)
AdminGET / POST / DELETE /admin/llm/*LLM config
AdminGET / POST / DELETE /admin/excluded-*Suppressions
AdminGET / POST / PUT / DELETE /admin/notificationsNotifications
AdminGET / POST /admin/settings/*App settings
POST /api/pods/failed

Request body:

{
"pod_name": "my-app-7d9f8b6c4-abc12",
"namespace": "default",
"node_name": "worker-1",
"failure_reason": "CrashLoopBackOff",
"failure_message": "Back-off restarting failed container",
"creation_timestamp": "2024-01-15T10:30:00Z",
"events": [...],
"container_statuses": [...],
"manifest": "apiVersion: v1\nkind: Pod\n...",
"logs": "Error: Database connection failed..."
}

Response 200:

{
"id": 1,
"pod_name": "my-app-7d9f8b6c4-abc12",
"namespace": "default",
"failure_reason": "CrashLoopBackOff",
"solution": "## Root Cause\n...",
"events": [...],
"container_statuses": [...],
"timestamp": "2024-01-15T10:30:00Z"
}
GET /api/pods/failed

Returns all active (non-dismissed) failures.

GET /api/pods/history
GET /api/pods/ignored
PUT /api/pods/{pod_id}/status
{
"status": "investigating"
}

Valid: new, investigating, resolved, ignored.

DELETE /api/pods/failed/{pod_id}
PUT /api/pods/ignored/{pod_id}/restore
POST /api/pods/failed/{pod_id}/retry-solution
GET /api/pods/{namespace}/{pod_name}/logs
?container=app
&tail_lines=100
&previous=false
GET /api/pods/{namespace}/{pod_name}/logs/stream
?container=app
&tail_lines=100
&token=<SERVICE_TOKEN>
POST /api/security/findings
{
"resource_type": "Pod",
"resource_name": "my-app-7d9f8b6c4-abc12",
"namespace": "default",
"check_name": "privileged_container",
"severity": "critical",
"message": "Container 'app' is running in privileged mode",
"remediation": "Remove 'privileged: true' from securityContext",
"details": {"container": "app", "field": "securityContext.privileged"}
}
GET /api/security/findings
DELETE /api/security/findings/{id}
PUT /api/security/findings/{id}/restore
POST /api/security/scan/clear
DELETE /api/security/findings/resource/{type}/{ns}/{name}
POST /api/security/findings/{id}/fix

Returns the LLM-generated remediation.

GET /api/security/trusted-registries
POST /api/security/trusted-registries { "registry": "..." }
DELETE /api/security/trusted-registries/{registry}
POST /api/mirror/preview/{pod_id}

Returns:

{
"fixed_manifest": "apiVersion: v1\nkind: Pod\n...",
"explanation": "## Changes Made\n1. Added resource limits...",
"is_fallback": false
}
POST /api/mirror/deploy/{pod_id}
{
"ttl_seconds": 180,
"manifest": "apiVersion: v1\nkind: Pod\n..." // optional, overrides preview
}

Returns:

{
"mirror_id": "abc123",
"mirror_pod_name": "my-app-mirror-abc123",
"namespace": "default",
"status": "Pending",
"ttl_seconds": 180,
"created_at": "2026-03-26T10:30:00Z",
"fixed_manifest": "...",
"explanation": "..."
}
GET /api/mirror/status/{mirror_id}
DELETE /api/mirror/{mirror_id}
GET /api/mirror/active
GET /api/admin/settings/mirror-ttl
PUT /api/admin/settings/mirror-ttl { "seconds": 300 }

Range: 30 – 3600 seconds. Admin role required for PUT.

Introduced in 2.3.2. All endpoints gated by require_read.

GET /api/diagram/namespaces
{ "namespaces": ["default", "kube-system", "kure-system"] }
GET /api/diagram/namespace/{namespace}
{
"nodes": [{ "id": "...", "kind": "Deployment", "name": "...", "namespace": "..." }],
"edges": [{ "id": "...", "source": "...", "target": "...", "kind": "owns" }],
"groups": [{ "id": "...", "label": "my-app", "members": ["..."] }]
}
GET /api/diagram/workload/{namespace}/{kind}/{name}

Valid kind values: Deployment, StatefulSet, DaemonSet, Job, CronJob. Same response shape as the namespace graph.

GET /api/diagram/manifest/{namespace}/{kind}/{name}

Returns the live manifest as YAML. Rejects kind=Secret with HTTP 403 by design — the backend ServiceAccount has no read access to Secrets. Synthesized kinds (Permission, Subject:User, Subject:Group) are rejected with HTTP 400 because they have no underlying manifest.

Added in 2.3.3.

GET /api/diagram/roles
{
"cluster_roles": [{ "name": "..." }],
"roles": [{ "namespace": "...", "name": "..." }]
}

Added in 2.3.3.

GET /api/diagram/role/{namespace}/{name}

Same response shape as the namespace graph. Nodes include the Role, its RoleBindings, synthesized Permission nodes (one per (apiGroup, resource) tuple, with verbs and resourceNames in metadata), and Subject:User / Subject:Group / Subject:ServiceAccount nodes.

Added in 2.3.3.

GET /api/diagram/clusterrole/{name}

Same shape as the per-Role graph but for ClusterRoles + ClusterRoleBindings.

GET /api/admin/llm/status
POST /api/admin/llm/config { "provider": "...", "api_key": "...", "model": "..." }
POST /api/admin/llm/test { "provider": "...", "api_key": "...", "model": "..." }
DELETE /api/admin/llm/config

See LLM Providers for supported provider/model combinations.

GET /api/admin/excluded-namespaces
POST /api/admin/excluded-namespaces { "namespace": "kube-system" }
DELETE /api/admin/excluded-namespaces/{namespace}
GET /api/admin/excluded-pods
POST /api/admin/excluded-pods { "pod_name": "test-*" }
DELETE /api/admin/excluded-pods/{pod_name}
GET /api/admin/notifications
POST /api/admin/notifications
PUT /api/admin/notifications/{provider}
DELETE /api/admin/notifications/{provider}
POST /api/admin/notifications/{provider}/test

Sample body:

{
"provider": "slack",
"enabled": true,
"config": { "webhook_url": "https://hooks.slack.com/services/..." }
}
GET /api/admin/settings/{key}
POST /api/admin/settings/{key} { "value": "10080" }

Common keys:

  • history_retention_minutes — auto-delete resolved pods after N minutes (0 = disabled)
  • ignored_retention_minutes — auto-delete ignored pods after N minutes (0 = disabled)
WS /api/ws

Push messages from the backend:

{ "type": "pod_failure", "data": { "id": 1, "pod_name": "...", "solution": "..." } }
{ "type": "pod_deleted", "data": { "namespace": "default", "pod_name": "..." } }
{ "type": "solution_updated", "data": { "id": 1, "solution": "..." } }
{ "type": "security_finding", "data": { "id": 1, "severity": "critical", "message": "..." } }
{ "type": "namespace_exclusion", "data": { "namespace": "kube-system", "action": "excluded" } }
{ "type": "trusted_registry_change", "data": { "registry": "...", "action": "added" } }
{ "type": "pod_status_change", "data": { "id": 1, "status": "investigating" } }
{ "type": "security_rescan_status", "data": { "status": "started", "reason": "trusted_registry_change" } }
StatusBody
400{ "detail": "Pod name and namespace are required" }
401{ "detail": "Not authenticated" }
403{ "detail": "Secret manifests are not readable by design." }
404{ "detail": "Pod failure not found" }
500{ "detail": "Internal server error..." }
503{ "detail": "Kubernetes client not available" }
  • Swagger UI: http://<backend-host>:8000/docs
  • ReDoc: http://<backend-host>:8000/redoc