Skip to content

Web UI endpoints

Read-only endpoints for the web UI.

Endpoint Summary
GET /v1/summary Fleet and per-cluster totals
GET /v1/clusters Clusters with agent heartbeat and counts
GET /v1/workloads Workloads with their latest recommendation
GET /v1/workloads/facets Filter values with workload counts
GET /v1/workloads/{id} Workload detail with per-container explanation
GET /v1/workloads/{id}/usage Usage, request, limit and recommendation time series
GET /v1/workloads/{id}/history Past recommendations and audit events of a workload
GET /v1/savings/trend Estimated monthly savings over time
GET /v1/savings/realized Realized savings from applied changes
GET /v1/savings/realized/node-cost Node cost trend of a cluster, next to the released requests
GET /v1/workloads/{id}/savings/realized Realized savings of one workload
GET /v1/workloads/{id}/effective-policy Precedence chain and winning value per field
GET /v1/workloads/{id}/override The workload's hub override policy
PUT /v1/workloads/{id}/override Create or replace the workload's override
DELETE /v1/workloads/{id}/override Clear the workload's override
POST /v1/workloads/{id}/approve Approve the current recommendation once
GET /v1/clusters/{cluster}/readiness Readiness state and check results of a cluster
POST /v1/clusters/{cluster}/readiness/recheck Re-run the readiness checks now
GET /v1/clusters/{cluster}/readiness/history State transitions and check status changes
GET /v1/clusters/{cluster}/capacity Node capacity, the node estimate after the open recommendations, and consolidation blockers

Fleet and per-cluster totals

GET /v1/summary

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Totals over the latest recommendation of every live workload. Workloads the agent never reported count as audit / Pending (the global default). A team-scoped caller gets the totals of its teams' workloads only, and only the clusters where it has workloads; teams groups the same totals by team (docs/teams.md).

Responses

Status Description Body
200 Summary. FleetSummary
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Clusters with agent heartbeat and counts

GET /v1/clusters

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Responses

Status Description Body
200 Clusters, ordered by name. ClusterList
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Workloads with their latest recommendation

GET /v1/workloads

Accepts: bearer token with role ui or session of a user with role viewer or higher.

One row per live workload, including workloads that have no recommendation yet (their recommendation fields are absent). All filters are combined with AND; repeatable filters match any of their values. A team-scoped caller sees only the workloads of its teams, and total counts only those (docs/teams.md).

Parameters

Name In Type Description
cluster query array of string
namespace query array of string
kind query array of WorkloadKind (enum)
mode query array of Mode (enum) Matches if the CPU or the memory mode is one of the values.
riskFlag query array of RiskFlag (enum) Matches if the workload has any of the flags.
gpu query array of GPUFilter (enum) GPU workloads. any matches every workload that requests nvidia.com/gpu; the other values match GPUUsage.status. Matches if any of the values matches.
team query array of string Team ids (unassigned = workloads in no team); matches any of them.
minSavings query number Minimum total estimated monthly savings in USD.
q query string Case-insensitive substring match on namespace and workload name. max length 253
sort query string one of savings, confidence, name; default savings
order query string Default desc for savings and confidence, asc for name. one of asc, desc
limit query integer min 1; max 500; default 50
continue query string Token from a previous page's continue field.

Responses

Status Description Body
200 Workloads. WorkloadList
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Filter values with workload counts

GET /v1/workloads/facets

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Counts of live workloads per filter value, for building the filters of the workload list. Like every read, only the workloads of the caller's teams are counted (docs/teams.md). Takes the same filters as GET /v1/workloads. Each facet is counted with every filter applied except its own (so a multi-select keeps showing the other values of that facet); total applies all filters and equals WorkloadList.total. A workload counts once per distinct value: in modes under both its CPU and its memory mode, in riskFlags under each of its flags, in gpu under its GPU status. Values with zero workloads are omitted. Items are sorted by value.

Parameters

Name In Type Description
cluster query array of string
namespace query array of string
kind query array of WorkloadKind (enum)
mode query array of Mode (enum) Matches if the CPU or the memory mode is one of the values.
riskFlag query array of RiskFlag (enum) Matches if the workload has any of the flags.
gpu query array of GPUFilter (enum) GPU workloads. any matches every workload that requests nvidia.com/gpu; the other values match GPUUsage.status. Matches if any of the values matches.
team query array of string Team ids (unassigned = workloads in no team); matches any of them.
minSavings query number Minimum total estimated monthly savings in USD.
q query string Case-insensitive substring match on namespace and workload name. max length 253

Responses

Status Description Body
200 Facets. WorkloadFacets
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Workload detail with per-container explanation

GET /v1/workloads/{id}

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout

Responses

Status Description Body
200 Workload detail. WorkloadDetail
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem

Usage, request, limit and recommendation time series

GET /v1/workloads/{id}/usage

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Per container. usage is the maximum across the workload's pods at each step (what a per-pod request has to cover); usageAvg is the mean across pods. request, limit and recommendation (recommended request) are step functions. Values are cores for cpu and bytes for memory.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
resource query ResourceName (enum), required one of cpu, memory
container query string Only this container.
from query string (date-time) Inclusive start. Default to minus 7 days.
to query string (date-time) Exclusive end. Default now.
step query string Resolution (Go duration). Default chosen so the result has at most 1000 points. example 5m, 1h

Responses

Status Description Body
200 Time series. UsageSeries
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem

Past recommendations and audit events of a workload

GET /v1/workloads/{id}/history

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Both lists are newest first and capped at limit entries each.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
from query string (date-time) Inclusive start. Default to minus 7 days.
to query string (date-time) Exclusive end. Default now.
limit query integer min 1; max 1000; default 100

Responses

Status Description Body
200 History. WorkloadHistory
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem

Estimated monthly savings over time

GET /v1/savings/trend

Accepts: bearer token with role ui or session of a user with role viewer or higher.

At each step: the sum of the estimated monthly savings of the recommendation that was latest at that time, over the workloads live at that time. Estimated, not realized (realized savings: GET /v1/savings/realized). Points are aligned to multiples of step (UTC); a point at time t holds the value at the end of its bucket, min(t + step, to), so with the default to (now) the last point equals the current GET /v1/summary totals.

Parameters

Name In Type Description
cluster query array of string
team query array of string Team ids (unassigned = workloads in no team); matches any of them.
groupBy query string none returns one fleet series; cluster one series per cluster; team one series per team (unassigned for workloads in no team). Team totals are recorded by the recommender runs since teams exist; with a team filter, groupBy=team or a team-scoped caller the series start there. one of none, cluster, team; default none
from query string (date-time) Inclusive start. Default to minus 7 days.
to query string (date-time) Exclusive end. Default now.
step query string Resolution (Go duration). Default chosen so the result has at most 1000 points. example 5m, 1h

Responses

Status Description Body
200 Savings trend. SavingsTrend
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Realized savings from applied changes

GET /v1/savings/realized

Accepts: bearer token with role ui or session of a user with role viewer or higher.

What the changes Kerf applied (auto-patch or approve once) actually saved: per workload and hour, the requests released (the from minus to requests of every applied and rolled_back event, cumulative, so rollbacks and later increases subtract; a released event ends the claim) times the replicas that ran in that hour (kube-state-metrics) times the cluster's rates of that hour (as stored by the recommender run of the time). The hub leader computes it hourly from the stored history, including changes applied before this endpoint existed. Realized, not estimated: never add these amounts to Savings (estimated, if applied). Method and SQL/PromQL: docs/realized-savings.md.

Buckets are aligned to UTC days or months; the first bucket starts at from truncated to its bucket. Hours at or after computedThrough are not computed yet.

Parameters

Name In Type Description
cluster query array of string
namespace query array of string
team query array of string Team ids (unassigned = workloads in no team); matches any of them.
from query string (date-time) Inclusive start. Default 12 months before to (step=month) or 30 days (step=day).
to query string (date-time) Exclusive end. Default now.
step query RealizedStep (enum) one of day, month

Responses

Status Description Body
200 Realized savings. RealizedSavings
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Node cost trend of a cluster, next to the released requests

GET /v1/savings/realized/node-cost

Accepts: bearer token with role ui or session of a user with role viewer or higher.

Per bucket: the average hourly cost of the cluster's priced nodes (kerf_node_hourly_cost_usd), their number, and the ratio of the scheduled pods' requests to the nodes' allocatable capacity, next to the requests Kerf's applied changes released (times replicas). The relation is correlated: if the node autoscaler turned released requests into fewer nodes, the lines show it, but Kerf does not claim one caused the other.

Parameters

Name In Type Description
cluster query string, required pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$; example ro-spoke-1
from query string (date-time) Inclusive start. Default 30 days before to.
to query string (date-time) Exclusive end. Default now.
step query NodeCostStep (enum) Default hour up to 7 days, day beyond. one of hour, day

Responses

Status Description Body
200 Node cost trend. NodeCostTrend
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown cluster. Problem

Realized savings of one workload

GET /v1/workloads/{id}/savings/realized

Accepts: bearer token with role ui or session of a user with role viewer or higher.

As GET /v1/savings/realized, for one workload. Also answers for a deleted workload that has realized history.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
from query string (date-time) Inclusive start. Default 30 days before to (step=day) or 12 months (step=month).
to query string (date-time) Exclusive end. Default now.
step query RealizedStep (enum) Default day. one of day, month

Responses

Status Description Body
200 Realized savings. RealizedSavings
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem

Precedence chain and winning value per field

GET /v1/workloads/{id}/effective-policy

Accepts: session of a user with role viewer or higher or bearer token with role ui.

Computed by the hub from the hub-managed policies, the cluster's reported policy inventory (Git policies), the agent's reported cluster defaults and the workload's annotations and labels as last reported. Layers from lowest to highest precedence: built-in defaults → global default → cluster default (chart value) → cluster default (hub) → the winning policy (highest priority, ties by name) → workload override (hub) → annotations. fields lists every field with its value and the layer that set it. agentModes is what the agent last reported, so the UI can show a difference (e.g. before the next pull).

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout

Responses

Status Description Body
200 Effective policy. EffectivePolicy
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem

The workload's hub override policy

GET /v1/workloads/{id}/override

Accepts: session of a user with role viewer or higher or bearer token with role ui.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout

Responses

Status Description Body
200 Override. AdminPolicy
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem

Create or replace the workload's override

PUT /v1/workloads/{id}/override

Accepts: session of a user with role operator or higher or bearer token with role admin.

Stores a hub policy of type workload-override named ro-override-<16 hex of sha256("<namespace>/<kind>/<name>")>, priority 900000, sent only to the workload's cluster, with selector {namespaces: [ns], kinds: [kind], workloads: [ref]}. Creating one needs no If-Match; replacing an existing one does (428 without it). Setting a mode to auto-patch on a cluster with environment prod needs an admin (403, code admin_required). "Exclude" is an override with both modes off. Records OverrideSet. Setting a mode to auto-patch for a cluster that is not AutomationReady gives 409, code cluster_not_automation_ready, unless an admin sends overrideReadiness: true.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
If-Match header string ETag ("<version>") of the object being changed; checked when given (412 if stale).
X-CSRF-Token header string Required when the request is authenticated with the session cookie.

Request body (application/json, required): WorkloadOverrideInput

Responses

Status Description Body
200 Saved. AdminPolicy
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem
409 The change conflicts with the current state (code says how). Problem
412 If-Match does not match the current version (code version_conflict). Problem
428 If-Match is required (code precondition_required). Problem

Clear the workload's override

DELETE /v1/workloads/{id}/override

Accepts: session of a user with role operator or higher or bearer token with role admin.

Soft-deletes the override policy; the workload inherits again. Records OverrideCleared.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
If-Match header string, required ETag ("<version>") of the object being changed (428 if missing, 412 if stale).
X-CSRF-Token header string Required when the request is authenticated with the session cookie.

Request body (application/json, required): ChangeReason

Responses

Status Description Body
204 Cleared.
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem
412 If-Match does not match the current version (code version_conflict). Problem
428 If-Match is required (code precondition_required). Problem

Approve the current recommendation once

POST /v1/workloads/{id}/approve

Accepts: session of a user with role operator or higher or bearer token with role admin.

Records an approval for recommendationID, which must be the workload's latest recommendation (409, code recommendation_stale). Only for a workload whose effective mode for at least one resource is audit (409, code not_in_audit). The agent applies that recommendation once, with all guardrails, as if the audit resources were auto-patch, and emits applied with reason ApprovedOnce; the workload stays in audit. A new approval replaces an earlier unconsumed one. Records WorkloadApproved. On a cluster that is not AutomationReady: 409, code cluster_not_automation_ready, unless an admin sends overrideReadiness: true.

Parameters

Name In Type Description
id path string, required Workload id <cluster>/<namespace>/<kind>/<name>, URL-encoded as one segment. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?/[^/]+/(Deployment\|StatefulSet\|DaemonSet\|CronJob)/[^/]+$; example ro-spoke-1/payments/Deployment/checkout
X-CSRF-Token header string Required when the request is authenticated with the session cookie.

Request body (application/json, required): ApprovalRequest

Responses

Status Description Body
201 Approved. Approval
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown workload id. Problem
409 The change conflicts with the current state (code says how). Problem

Readiness state and check results of a cluster

GET /v1/clusters/{cluster}/readiness

Accepts: session of a user with role viewer or higher or bearer token with role ui.

The latest result of every check (hub metrics checks and agent self-checks), the state they imply and what blocks the next state. Checks never run yet have status unknown.

Parameters

Name In Type Description
cluster path string, required Cluster name. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$; example ro-spoke-1

Responses

Status Description Body
200 Readiness. ClusterReadiness
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown cluster. Problem

Re-run the readiness checks now

POST /v1/clusters/{cluster}/readiness/recheck

Accepts: session of a user with role operator or higher or bearer token with role admin.

Queues the hub metrics checks and sets the recheck flag in the cluster's config, so the agent re-runs its self-checks on its next pull. Results appear in GET /v1/clusters/{cluster}/readiness as they arrive. Not audited.

Parameters

Name In Type Description
cluster path string, required Cluster name. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$; example ro-spoke-1
X-CSRF-Token header string Required when the request is authenticated with the session cookie.

Responses

Status Description Body
202 Re-check queued. RecheckAccepted
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown cluster. Problem

State transitions and check status changes

GET /v1/clusters/{cluster}/readiness/history

Accepts: session of a user with role viewer or higher or bearer token with role ui.

Only changes are stored (a check's status or the state), newest first.

Parameters

Name In Type Description
cluster path string, required Cluster name. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$; example ro-spoke-1
from query string (date-time) Inclusive start. Default to minus 7 days.
to query string (date-time) Exclusive end. Default now.
limit query integer min 1; max 1000; default 100
continue query string Token from a previous page's continue field.

Responses

Status Description Body
200 History. ReadinessHistory
400 The request is malformed or fails validation. Problem
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown cluster. Problem

Node capacity, the node estimate after the open recommendations, and consolidation blockers

GET /v1/clusters/{cluster}/capacity

Accepts: session of a user with role viewer or higher or bearer token with role ui.

Built from the agent's last capacity report (WorkloadStatusBatch.capacity), the open recommendations and the pricing series. The node estimate is an estimate: a first-fit-decreasing bin packing of pod requests per node pool, described in docs/node-savings.md (estimate.methodURL). Kerf never creates, deletes or drains nodes. reportedAt is absent when the agent never sent a capacity report (agents before this feature, or --capacity=false); the other fields are then empty.

Parameters

Name In Type Description
cluster path string, required Cluster name. pattern ^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$; example ro-spoke-1

Responses

Status Description Body
200 Capacity. ClusterCapacity
401 Missing or invalid bearer token. Problem
403 The token is not allowed to access this cluster, the role is too low (role_forbidden), or the caller's team bindings do not cover the endpoint or the workload (scope_forbidden, docs/teams.md). Problem
404 Unknown cluster. Problem