API Reference
Clusters
List and fetch the Kubernetes clusters in your tenant. Filter by provider, region, environment, and status. Default sort is hourly run rate descending.
Two endpoints cover the cluster surface: a paginated list with filters and a single-cluster lookup by UUID. Both return a Cluster body with metadata, capacity, utilization, and cost.
GET /v1/clusters returns the inventory across every cluster the API key is allowed to see. GET /v1/clusters/{cluster_id} returns one cluster's full body. Both require the clusters:read scope. Neither accepts ?cost_mode=; see Cost Modes for details.
Staleness
metadata.is_stale flips to true when the last agent heartbeat is older than 180 seconds or last_seen_at is null. While stale, utilization and cost reflect the last successful agent snapshot, not live data.
- Stale clusters are excluded from
Organization.utilization.counts.connected_clusters. They still count towardclusters. See Organization. - Staleness is orthogonal to
status. A cluster can bestatus=activeandis_stale=truesimultaneously — the agent has gone quiet without the cluster being marked disconnected. Filter onis_staleto detect this, not onstatus.
List clusters
GET /v1/clusters
Required scope: clusters:read
Returns the cluster inventory across the API key's allowed clusters. Default sort is cost.current_run_rate_hourly DESC.
Filters combine with AND. Each filter is a comma-separated list interpreted as an OR within that filter: provider=aws,gcp means "AWS or GCP", status=active,disconnected means "either status". Pass standard pagination via limit, cursor, and include_total; see Pagination & Filtering for the full cursor contract.
Query parameters
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
limit | integer | 100 | 1..500 | Page size. |
cursor | string | - | - | Opaque pagination token from a previous response. |
include_total | boolean | false | true, false | Include meta.pagination.total_count. Opt-in. |
provider | string | - | aws, gcp, azure, on-prem (csv) | Filter by cloud provider. |
region | string | - | - | Filter by region (csv). |
environment | string | - | production, non-production, staging, dev (csv) | Filter by environment tag. |
status | string | - | pending, active, disconnected, error, discovered (csv) | Filter by cluster status. Lowercase only. |
Enum filters are case-sensitive: provider=AWS returns a 422, not an empty list. The error response echoes the allowed set under error.details[0].allowed.
Example request
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/clusters?provider=aws,gcp&status=active&limit=20&include_total=true"Example response
1{
2 "data": [
3 {
4 "id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
5 "kind": "Cluster",
6 "metadata": {
7 "name": "prod-eu-west-1",
8 "provider": "aws",
9 "service": "EKS",
10 "region": "eu-west-1",
11 "availability_zones": ["eu-west-1a", "eu-west-1b", "eu-west-1c"],
12 "environment": "production",
13 "status": "active",
14 "is_stale": false,
15 "k8s_version": "1.29.5",
16 "agent_version": "1.18.2",
17 "discovery_source": "agent",
18 "created_at": "2025-11-08T14:22:31Z",
19 "last_seen_at": "2026-05-21T10:29:42Z"
20 },
21 "capacity": {
22 "cpu": { "total_cores": 256.0, "allocatable_cores": 240.8 },
23 "memory": { "total_bytes": 1099511627776, "allocatable_bytes": 1023820300288 },
24 "gpu": { "total": 8, "allocatable": 8, "model": "NVIDIA A10G" },
25 "storage": { "total_bytes": 21474836480000 },
26 "pods": { "allocatable": 7392 }
27 },
28 "utilization": {
29 "cpu": { "requested_cores": 184.2, "used_cores": 142.7, "utilization_percent": 55.8 },
30 "memory": { "requested_bytes": 769527797760, "used_bytes": 612918427648, "utilization_percent": 55.7 },
31 "gpu": { "utilization_percent": 62.4, "memory_used_bytes": 12884901888, "memory_total_bytes": 21474836480 },
32 "network": { "rx_bytes_total": 84293817394, "tx_bytes_total": 67419283746 },
33 "restarts_total": 142,
34 "oom_kills_total": 6,
35 "counts": {
36 "nodes": 32,
37 "namespaces": 24,
38 "workloads": 412,
39 "deployments": 287,
40 "statefulsets": 64,
41 "daemonsets": 12,
42 "jobs": 38,
43 "cronjobs": 11,
44 "pods": 1247,
45 "running_pods": 1218,
46 "containers": 2891,
47 "running_containers": 2842,
48 "persistent_volumes": 94
49 }
50 },
51 "cost": {
52 "current_run_rate_hourly": { "amount": "147.2400", "currency": "USD" },
53 "last_updated_at": "2026-05-21T10:29:48Z"
54 }
55 },
56 {
57 "id": "a8d3e1b2-f4c6-4789-9bde-2345678901cd",
58 "kind": "Cluster",
59 "metadata": {
60 "name": "staging-us-central1",
61 "provider": "gcp",
62 "service": "GKE",
63 "region": "us-central1",
64 "availability_zones": ["us-central1-a", "us-central1-b"],
65 "environment": "staging",
66 "status": "active",
67 "is_stale": false,
68 "k8s_version": "1.30.1",
69 "agent_version": "1.18.2",
70 "discovery_source": "agent",
71 "created_at": "2026-02-17T11:04:09Z",
72 "last_seen_at": "2026-05-21T10:29:51Z"
73 },
74 "capacity": {
75 "cpu": { "total_cores": 96.0, "allocatable_cores": 88.4 },
76 "memory": { "total_bytes": 412316860416, "allocatable_bytes": 381344419840 },
77 "gpu": { "total": 0, "allocatable": 0, "model": "" },
78 "storage": { "total_bytes": 4294967296000 },
79 "pods": { "allocatable": 2640 }
80 },
81 "utilization": {
82 "cpu": { "requested_cores": 41.6, "used_cores": 28.9, "utilization_percent": 32.7 },
83 "memory": { "requested_bytes": 142473041920, "used_bytes": 98248129024, "utilization_percent": 25.8 },
84 "gpu": { "utilization_percent": 0.0, "memory_used_bytes": 0, "memory_total_bytes": 0 },
85 "network": { "rx_bytes_total": 18293742918, "tx_bytes_total": 12048372619 },
86 "restarts_total": 47,
87 "oom_kills_total": 1,
88 "counts": {
89 "nodes": 12,
90 "namespaces": 9,
91 "workloads": 88,
92 "deployments": 62,
93 "statefulsets": 14,
94 "daemonsets": 8,
95 "jobs": 3,
96 "cronjobs": 1,
97 "pods": 234,
98 "running_pods": 229,
99 "containers": 481,
100 "running_containers": 473,
101 "persistent_volumes": 22
102 }
103 },
104 "cost": {
105 "current_run_rate_hourly": { "amount": "42.1800", "currency": "USD" },
106 "last_updated_at": "2026-05-21T10:29:52Z"
107 }
108 }
109 ],
110 "meta": {
111 "request_id": "req_01J5K4A1B7C9DE2F4G6H8J0K2M",
112 "applied_at": "2026-05-21T10:30:00Z",
113 "pagination": {
114 "next_cursor": "eyJ2IjoxLCJhZnRlcl9pZCI6ImE4ZDNlMWIyLWY0YzYtNDc4OS05YmRlLTIzNDU2Nzg5MDFjZCIsImFmdGVyX3ZhbHVlIjoiNDIuMTgwMCIsInF1ZXJ5X2hhc2giOiJhM2I0YzVkNmU3ZjhnOWEwYjFjMmQzZTRmNWc2IiwiaXNzdWVkX2F0IjoxNzE2Mjg1MDAwfQ",
115 "has_more": true,
116 "limit": 20,
117 "total_count": 6
118 }
119 }
120}Two elements shown for brevity. next_cursor is displayed for shape clarity; a single-page response sets has_more: false and either omits next_cursor or returns it as an empty string.
Example error response
1{
2 "data": null,
3 "meta": {
4 "request_id": "req_01J5K4A1B7C9DE2F4G6H8J0K2N",
5 "applied_at": "2026-05-21T10:30:01Z"
6 },
7 "error": {
8 "code": "CLUSTER_NOT_FOUND",
9 "message": "cluster not found in tenant",
10 "details": [
11 { "field": "cluster_id", "reason": "not_found" }
12 ]
13 }
14}That code comes back from GET /v1/clusters/{cluster_id} when the UUID is well-formed but no cluster in your tenant matches. See Error Handling for the full mapping.
Common errors
| HTTP | error.code | When |
|---|---|---|
| 400 | BAD_REQUEST | Malformed query, bad limit. |
| 400 | INVALID_CURSOR | cursor couldn't be decoded. |
| 401 | UNAUTHORIZED | Missing or invalid Bearer token. |
| 403 | FORBIDDEN | Token lacks the clusters:read scope. |
| 410 | CURSOR_EXPIRED | Cursor older than 24h or query parameters changed since it was issued. |
| 422 | VALIDATION_ERROR | Enum filter value isn't in the allowed set (e.g. provider=aliyun, status=Active). |
| 422 | INVALID_COST_MODE | ?cost_mode= was supplied, not accepted on this endpoint. |
| 429 | RATE_LIMITED | Per-key quota exceeded. |
| 500 | INTERNAL_ERROR | Server-side failure. |
Get cluster by ID
GET /v1/clusters/{cluster_id}
Required scope: clusters:read
Returns one cluster's full body, the same shape as a data[] element on the list endpoint.
Path parameters
| Name | Type | Description |
|---|---|---|
cluster_id | UUID | Cluster identifier. Must be a valid UUID, INVALID_CLUSTER_ID (400) otherwise. |
Example request
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/clusters/b7e22c91-8d34-4f5a-9c1e-0d8e3a4b5f76"Example response
Returns a single Cluster object. Same shape as one element of the List clusters response above, wrapped directly under data (no array, no pagination in meta).
1{
2 "data": {
3 "id": "b7e22c91-8d34-4f5a-9c1e-0d8e3a4b5f76",
4 "kind": "Cluster",
5 "metadata": { "name": "prod-us-east-1", "provider": "aws", "service": "EKS", "region": "us-east-1", "environment": "production", "status": "active", "is_stale": false, "...": "..." },
6 "capacity": { "...": "..." },
7 "utilization": { "...": "..." },
8 "cost": { "current_run_rate_hourly": { "amount": "98.1200", "currency": "USD" }, "last_updated_at": "2026-05-21T10:29:48Z" }
9 },
10 "meta": {
11 "request_id": "req_01J5K4B3D8F0HJ4K6M8N0P2Q4R",
12 "applied_at": "2026-05-21T10:30:00Z"
13 }
14}For the complete field list, see the canonical example in List clusters or the OpenAPI spec.
Common errors
| HTTP | error.code | When |
|---|---|---|
| 400 | INVALID_CLUSTER_ID | cluster_id isn't a valid UUID. |
| 401 | UNAUTHORIZED | Missing or invalid Bearer token. |
| 403 | FORBIDDEN | Token lacks the clusters:read scope. |
| 403 | CLUSTER_ACCESS_DENIED | UUID is valid and the cluster exists, but the API key's allowlist excludes it. |
| 404 | CLUSTER_NOT_FOUND | UUID is well-formed but no cluster in the tenant matches. |
| 422 | INVALID_COST_MODE | ?cost_mode= was supplied. |
| 429 | RATE_LIMITED | Per-key quota exceeded. |
| 500 | INTERNAL_ERROR | Server-side failure. |
See also
- Namespaces, drill from a cluster into its namespaces and their cost breakdown.
- Workloads, list workloads scoped to one cluster via
/v1/clusters/{cluster_id}/workloads. - Nodes, node inventory and node-group aggregates per cluster.
- Organization, the tenant-wide rollup;
connected_clustersexcludes stale ones. - Cost Trends, hourly/daily/weekly/monthly cost time series for a single cluster.