KubeadaptDocsBack to site
Sign inStart free
DocsAPI ReferenceCLI
    • Overview
    • Authentication
    • Permission Scopes
Docs homev1Api ReferencePermission Scopes

API Reference

Permission Scopes

The nine Kubeadapt API read scopes, the endpoints each one covers, the cluster ACL model, the 403 details payload, and minimum-token recipes.


Every API key encodes one or more of the nine *:read scopes — there are no write, admin, or break-glass scopes. Scopes gate endpoint families; a separate cluster ACL on the same key narrows access to a subset of clusters within those endpoints. Operations that would require write access (creating teams, applying recommendations, rotating cluster credentials) live in the Kubeadapt dashboard, not the API.

The nine read scopes

organization:read

The tenant-level view: total clusters, total spend, month-to-date billed cost, savings potential. The dashboard endpoint is the only place where MTD and savings figures live.

Endpoints:

  • GET /v1/organization: the snapshot. Aggregate capacity, utilization, and cost across allowed clusters. Rejects ?cost_mode= (the org-level bill is one physical number).
  • GET /v1/organization/dashboard: the dashboard. Month-to-date billed cost, savings potential (current hourly potential + recommendation count), top-N clusters by run rate. Accepts ?cost_mode= and returns genuinely different numbers per mode.

clusters:read

Cluster inventory: enumerate clusters, look one up by ID, list cluster status.

Endpoints:

  • GET /v1/clusters: paginated list of clusters in the key's allow-list. Filters: provider, region, environment, status. Default sort by cost.current_run_rate_hourly DESC. Rejects ?cost_mode=.
  • GET /v1/clusters/{cluster_id}: single cluster body. Rejects ?cost_mode=.

namespaces:read

Kubernetes namespaces with namespace-level cost rollups, optionally filtered by cluster.

Endpoints:

  • GET /v1/namespaces: paginated cross-cluster list.
  • GET /v1/clusters/{cluster_id}/namespaces: paginated list scoped to one cluster.
  • GET /v1/clusters/{cluster_id}/namespaces/{namespace}: single namespace body.

All three accept ?cost_mode=. The response echoes the requested mode in meta.cost_mode and cost.cost_mode. Both modes currently return the same cost amount for namespace endpoints.

workloads:read

Deployments, StatefulSets, DaemonSets, and the pod sub-list scoped to a workload. The controller-granularity surface used by chargeback pipelines, anomaly detection, and rightsizing dashboards.

Endpoints:

  • GET /v1/workloads: paginated cross-cluster list. Filter ?kind= to one or more of Deployment, StatefulSet, DaemonSet.
  • GET /v1/clusters/{cluster_id}/workloads: paginated list scoped to one cluster.
  • GET /v1/workloads/{workload_uid}: single workload body.
  • GET /v1/workloads/{workload_uid}/pods: paginated pod list for the workload.

All four accept ?cost_mode=. Same as namespaces: the response echoes the requested mode, but both modes currently return the same cost amount for workload endpoints.

nodes:read

Kubernetes nodes plus the node-group aggregates derived from them. Both families share this scope; there is no separate node-groups:read.

Endpoints:

  • GET /v1/nodes: paginated cross-cluster list.
  • GET /v1/clusters/{cluster_id}/nodes: paginated list scoped to one cluster.
  • GET /v1/nodes/{node_uid}: single node body.
  • GET /v1/node-groups: cross-cluster node-group aggregates. Not paginated.
  • GET /v1/clusters/{cluster_id}/node-groups: node groups in one cluster. Not paginated.
  • GET /v1/clusters/{cluster_id}/node-groups/{name}: single node-group body.

Every node and node-group endpoint rejects ?cost_mode= with 422 INVALID_COST_MODE. Nodes are physical infrastructure; their cost is one number, not a mode choice.

recommendations:read

Cost and efficiency recommendations with savings projections.

Endpoints:

  • GET /v1/recommendations: paginated list. Filters: cluster_id, namespace, recommendation_type (public API surfaces only workload_rightsizing), status (pending, applied, dismissed, archived), risk_level (low, medium, high), priority (low, medium, high), resource_type (Deployment, StatefulSet, DaemonSet, Pod, Node), workload_uid, min_savings_hourly.
  • GET /v1/recommendations/{rec_id}: single recommendation body, including a metrics_snapshot field.

Both endpoints reject ?cost_mode=. Recommendation savings use a fixed pricing model and are mode-agnostic.

teams:read

Team identity and the workload assignments that attach cost to teams. The scope a finance chargeback pipeline requires.

Endpoints:

  • GET /v1/teams: paginated team list with month-to-date cost rollups.
  • GET /v1/teams/{team_id}: single team body.
  • GET /v1/teams/{team_id}/assignments: paginated list of the workloads attributed to this team.

All three accept ?cost_mode= and return different cost figures per mode.

departments:read

Department identity and rolled-up department cost. Departments sit one level above teams in the attribution hierarchy.

Endpoints:

  • GET /v1/departments: paginated department list.
  • GET /v1/departments/{dept_id}: single department body, including child team summaries.

Both accept ?cost_mode= and return different cost figures per mode.

cost_explorer:read

Aggregated cost queries with grouping, filtering, and KPI summaries via Cost Explorer.

Endpoints:

  • POST /v1/cost-explorer/query: paginated cost rows + summary KPIs. The only POST in /v1. Uses offset pagination (page/per_page) and accepts ?cost_mode=.

cost_explorer:read does not imply or substitute for any other scope; if your integration needs the rolled-up cost-explorer view and the per-resource endpoints, mint a key with both.

The scope-to-endpoint table

For copy-paste into your integration's docs:

ScopeEndpoints
organization:read/v1/organization, /v1/organization/dashboard, /v1/organizations/dashboard/cost-trend
clusters:read/v1/clusters, /v1/clusters/{id}, /v1/clusters/{id}/cost-trend
namespaces:read/v1/namespaces, /v1/clusters/{id}/namespaces, /v1/clusters/{id}/namespaces/{ns}, /v1/clusters/{id}/namespaces/{ns}/cost-trend
workloads:read/v1/workloads, /v1/clusters/{id}/workloads, /v1/workloads/{uid}, /v1/workloads/{uid}/pods, /v1/clusters/{id}/workloads/by-uid/{uid}/cost-trend
nodes:read/v1/nodes, /v1/clusters/{id}/nodes, /v1/nodes/{uid}, /v1/node-groups, /v1/clusters/{id}/node-groups, /v1/clusters/{id}/node-groups/{name}, /v1/clusters/{id}/node-groups/{name}/cost-trend
recommendations:read/v1/recommendations, /v1/recommendations/{id}
teams:read/v1/teams, /v1/teams/{id}, /v1/teams/{id}/assignments
departments:read/v1/departments, /v1/departments/{id}
cost_explorer:read/v1/cost-explorer/query

A request to an endpoint not covered by any of your key's scopes returns 403 FORBIDDEN with the missing scope in error.details[0].

Cluster ACLs

Scopes are the first axis of authorization. Cluster ACLs are the second.

A key minted with clusters:read and an allow-list of three cluster UUIDs sees only those three clusters: GET /v1/clusters returns the three, GET /v1/clusters/{cluster_id} for a fourth returns 403 CLUSTER_ACCESS_DENIED. The allow-list applies to every cluster-scoped path, regardless of which scope opens it. Asking for a workload in a forbidden cluster, a namespace in a forbidden cluster, or a node in a forbidden cluster all return 403.

The allow-list is tri-state (nil, [], [ids]) — see Authentication § The cluster ACL tri-state for the full table.

Cross-cluster list endpoints (/v1/clusters, /v1/workloads, /v1/namespaces, etc.) return only the clusters the API key can access; they do not return 403 on a mismatch. The 403 path triggers only when an integration asks for a specific cluster by ID that is not permitted.

The 403 details payload

Both 403 shapes are machine-parseable. Customers writing retry logic, UX messaging, or onboarding flows key off error.details[0].

For FORBIDDEN (missing scope):

json
1{
2  "data": null,
3  "meta": {
4    "request_id": "req_01J5K3V0Q7Y4XR8A2B3C5D7E9F",
5    "applied_at": "2026-05-21T10:30:00Z"
6  },
7  "error": {
8    "code": "FORBIDDEN",
9    "message": "API key is missing the required scope",
10    "details": [{ "required": "clusters:read" }]
11  }
12}

For CLUSTER_ACCESS_DENIED (blocked cluster):

json
1{
2  "data": null,
3  "meta": {
4    "request_id": "req_01J5K3V0Q7Y4XR8A2B3C5D7E9G",
5    "applied_at": "2026-05-21T10:30:01Z"
6  },
7  "error": {
8    "code": "CLUSTER_ACCESS_DENIED",
9    "message": "API key is not allowed to access this cluster",
10    "details": [{ "cluster_id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890" }]
11  }
12}

Minimum-token recipes

Three concrete starting points for common integrations. Each picks the smallest scope set that gets the job done.

Read-only dashboard exporter

Pulls cluster, namespace, workload, and node data into your own dashboarding stack (Grafana, Looker, Tableau, Metabase). Reads org-level summary for headline numbers.

Scopes:

  • organization:read
  • clusters:read
  • namespaces:read
  • workloads:read
  • nodes:read

Cluster ACL: leave it at nil (all clusters) for a centralized export. Lock it down by cluster if the exporter is per-region or per-business-unit.

Finance chargeback pipeline

Runs monthly. Pulls cost-by-team and cost-by-department, plus the org-level total for reconciliation. Does not touch infrastructure resources.

Scopes:

  • teams:read
  • departments:read
  • organization:read

Cluster ACL: nil. Chargeback aggregates across the whole tenant.

SRE savings dashboard

Surfaces optimization opportunities for a platform team. Lists active recommendations, filters by cluster, drills into nodes for the rightsizing details.

Scopes:

  • recommendations:read
  • clusters:read
  • nodes:read

Cluster ACL: nil for an org-wide view, or scope to the production clusters only if the dashboard is a production runbook.

Anti-patterns

A few patterns to avoid because they create operational pain later:

  • One omnibus key with every scope, used by everything. When something goes wrong (leak, compromised integration, key rotation) you have to coordinate across every consumer at once. Mint per integration.
  • Scopes a key "might need later". Speculative permissions widen the blast radius of a leak. Mint with the minimum scope set; mint a second key when the additional scope is actually needed.
  • Cluster ACL set to nil because filling it in is tedious. If the integration is logically scoped to a subset of clusters (per-BU exporter, per-region pipeline), encode that in the ACL. Saves you when a new cluster joins and you don't want it in the export by default.

See also

  • Authentication: the Bearer token format, minting and rotation, the 401 vs 403 distinction.
  • API Overview: base URL, envelope shape, rate limits, the resource-family index.
  • Error Handling: the full error code catalog including FORBIDDEN and CLUSTER_ACCESS_DENIED.

Related

  • Authentication
  • API Overview
  • Error Handling
PreviousAuthenticationAPI ReferenceNextPaginationAPI Reference

On this page

  • The nine read scopes
  • organization:read
  • clusters:read
  • namespaces:read
  • workloads:read
  • nodes:read
  • recommendations:read
  • teams:read
  • departments:read
  • costexplorer:read
  • The scope-to-endpoint table
  • Cluster ACLs
  • The 403 details payload
  • Minimum-token recipes
  • Read-only dashboard exporter
  • Finance chargeback pipeline
  • SRE savings dashboard
  • Anti-patterns
  • See also
Edit this page
Kubeadapt

Kubernetes FinOps platform. Cost visibility, rightsizing, and capacity planning that pays for itself in 30 days.

Product

  • Cost Monitoring
  • Cost Attribution
  • Workload Rightsizing
  • Recommendations
  • Smart Alerting
  • Best Practices
  • Network Cross-AZ

Resources

  • Documentation
  • Status Page
  • Feature Requests

Company

  • About Us
  • Security
  • Careers
  • Contact

© 2026 Kubeadapt. All rights reserved.

PrivacyTermsSecurity