Skip to content

API Reference

Nodes

List, filter, and inspect Kubernetes nodes across every connected cluster, including instance type, spot status, capacity, and physical hourly cost.

Last updated


Three endpoints cover the node surface: a cross-cluster flat list, a per-cluster scoped list, and a single-node lookup by Kubernetes metadata.uid. Filters include is_spot, instance_type, node_group, architecture, and capacity_type.

List nodes (cross-cluster)

GET /v1/nodes

Required scope: nodes:read

A flat, cost-sorted inventory of every node the API key can see, across every cluster in the allow-list.

Default sort is cost.current_run_rate_hourly descending.

Query parameters

NameTypeDefaultAllowed valuesDescription
limitinteger1001..500Page size.
cursorstring(none)(any)Opaque pagination token from a previous response.
include_totalbooleanfalsetrue, falseInclude meta.pagination.total_count.
sortstringcostcost, idcost puts the highest run rate first. id sorts by node UID, then cluster ID, an order that holds while you walk every page. See Sort policy.
cluster_idstring (csv)(none)UUIDsScope to one or more clusters.
node_groupstring (csv)(none)(any)Filter by node-group label value.
instance_typestring (csv)(none)(any)Filter by cloud instance type. Singular here; the response field on a node-group is the plural array metadata.instance_types.
zonestring (csv)(none)(any)Filter by availability zone.
is_spotboolean(none)true, falseSpot/preemptible vs on-demand.
is_readyboolean(none)true, falseKubernetes Ready condition.
architecturestring (csv)(none)amd64, arm64CPU architecture.
capacity_typestring (csv)(none)on-demand, spot, reserved, karpenterPricing capacity bucket as the cloud provider reports it.

Example request

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/nodes?is_spot=false&architecture=amd64&limit=50&include_total=true"

Example response

json
1{
2  "data": [
3    {
4      "id": "n1a2b3c4-d5e6-7890-abcd-ef0987654321",
5      "kind": "Node",
6      "metadata": {
7        "name": "ip-10-0-12-34.eu-west-1.compute.internal",
8        "cluster": {
9          "id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
10          "name": "prod-eu-west-1"
11        },
12        "node_role": "worker",
13        "instance_type": "m5.2xlarge",
14        "node_group": "prod-mixed",
15        "availability_zone": "eu-west-1a",
16        "region": "eu-west-1",
17        "is_spot": false,
18        "capacity_type": "on-demand",
19        "architecture": "amd64",
20        "operating_system": "linux",
21        "kubelet_version": "v1.29.4-eks-7c54e62",
22        "provider_id": "aws:///eu-west-1a/i-0a1b2c3d4e5f67890",
23        "is_ready": true,
24        "is_schedulable": true,
25        "labels": {
26          "kubernetes.io/arch": "amd64",
27          "node.kubernetes.io/instance-type": "m5.2xlarge",
28          "topology.kubernetes.io/zone": "eu-west-1a"
29        },
30        "created_at_k8s": "2026-04-22T15:08:11Z",
31        "last_seen_at": "2026-05-21T10:29:48Z"
32      },
33      "capacity": {
34        "cpu": { "total_cores": 8.0, "allocatable_cores": 7.91 },
35        "memory": { "total_bytes": 34359738368, "allocatable_bytes": 32212254720 },
36        "gpu": { "total": 0, "allocatable": 0, "model": "" },
37        "ephemeral_storage": { "total_bytes": 107374182400 },
38        "pods": { "allocatable": 58 }
39      },
40      "utilization": {
41        "cpu": { "used_cores": 6.32, "utilization_percent": 79.9 },
42        "memory": { "used_bytes": 25769803776, "utilization_percent": 80.0 },
43        "gpu": {
44          "utilization_percent": 0,
45          "memory_used_bytes": 0,
46          "memory_total_bytes": 0
47        },
48        "counts": { "pods": 24, "running_pods": 22 }
49      },
50      "cost": {
51        "current_run_rate_hourly": { "amount": "0.4960", "currency": "USD" },
52        "on_demand_equivalent_hourly": { "amount": "0.4960", "currency": "USD" },
53        "pricing_source": "aws-pricing-api",
54        "last_updated_at": "2026-05-21T10:29:48Z"
55      }
56    },
57    {
58      "id": "n2b3c4d5-e6f7-8901-bcde-f12345678901",
59      "kind": "Node",
60      "metadata": {
61        "name": "ip-10-0-15-78.eu-west-1.compute.internal",
62        "cluster": {
63          "id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
64          "name": "prod-eu-west-1"
65        },
66        "node_role": "worker",
67        "instance_type": "m5.2xlarge",
68        "node_group": "prod-mixed",
69        "availability_zone": "eu-west-1b",
70        "region": "eu-west-1",
71        "is_spot": true,
72        "capacity_type": "spot",
73        "architecture": "amd64",
74        "operating_system": "linux",
75        "kubelet_version": "v1.29.4-eks-7c54e62",
76        "provider_id": "aws:///eu-west-1b/i-1b2c3d4e5f6a78901",
77        "is_ready": true,
78        "is_schedulable": true,
79        "labels": {
80          "kubernetes.io/arch": "amd64",
81          "node.kubernetes.io/instance-type": "m5.2xlarge",
82          "node.kubernetes.io/lifecycle": "spot",
83          "topology.kubernetes.io/zone": "eu-west-1b"
84        },
85        "created_at_k8s": "2026-04-30T07:42:18Z",
86        "last_seen_at": "2026-05-21T10:29:49Z"
87      },
88      "capacity": {
89        "cpu": { "total_cores": 8.0, "allocatable_cores": 7.91 },
90        "memory": { "total_bytes": 34359738368, "allocatable_bytes": 32212254720 },
91        "gpu": { "total": 0, "allocatable": 0, "model": "" },
92        "ephemeral_storage": { "total_bytes": 107374182400 },
93        "pods": { "allocatable": 58 }
94      },
95      "utilization": {
96        "cpu": { "used_cores": 5.06, "utilization_percent": 64.0 },
97        "memory": { "used_bytes": 22441820160, "utilization_percent": 69.7 },
98        "gpu": {
99          "utilization_percent": 0,
100          "memory_used_bytes": 0,
101          "memory_total_bytes": 0
102        },
103        "counts": { "pods": 19, "running_pods": 19 }
104      },
105      "cost": {
106        "current_run_rate_hourly": { "amount": "0.1492", "currency": "USD" },
107        "on_demand_equivalent_hourly": { "amount": "0.4960", "currency": "USD" },
108        "pricing_source": "aws-pricing-api",
109        "last_updated_at": "2026-05-21T10:29:49Z"
110      }
111    }
112  ],
113  "meta": {
114    "request_id": "0196f1c2-acfc-7c1a-ac5d-915eb3d29dbc",
115    "applied_at": "2026-05-21T10:31:00Z",
116    "pagination": {
117      "next_cursor": "eyJ2IjoxLCJhZnRlcl9pZCI6Im4yYjNjNGQ1LWU2ZjctODkwMS1iY2RlLWYxMjM0NTY3ODkwMSIsImFmdGVyX3ZhbHVlIjoiMC4xNDkyIiwicXVlcnlfaGFzaCI6ImI0YzVkNmU3ZjhnOWgwaTFqMmszbDRtNW42cDciLCJpc3N1ZWRfYXQiOjE3MTYyODUwNjB9",
118      "has_more": true,
119      "limit": 50,
120      "total_count": 32
121    }
122  }
123}

Example error response

json
1{
2  "data": null,
3  "meta": {
4    "request_id": "0196f1c2-cc7c-7c4f-bad7-b8a7f1218867",
5    "applied_at": "2026-05-21T10:31:05Z"
6  },
7  "error": {
8    "code": "INVALID_COST_MODE",
9    "message": "cost_mode is not supported on this endpoint",
10    "details": [
11      { "field": "cost_mode", "reason": "not_supported_on_this_endpoint" }
12    ]
13  }
14}

Common errors

HTTPerror.codeWhen
400BAD_REQUESTBad cursor, limit out of range, malformed UUID.
401UNAUTHORIZEDMissing or invalid Bearer token.
403FORBIDDENToken lacks the nodes:read scope.
410CURSOR_EXPIREDCursor older than 24h or filter set changed.
422INVALID_COST_MODE?cost_mode= was supplied. This endpoint doesn't accept it.
422VALIDATION_ERRORis_spot, is_ready, architecture, capacity_type, or another filter has an unsupported value. The error detail names the offending field.
429RATE_LIMITED100 req/min/key by default. Honor Retry-After.

See Error Handling.

List nodes in cluster

GET /v1/clusters/{cluster_id}/nodes

Required scope: nodes:read

Same shape as the cross-cluster list, scoped to one cluster by path. All filters except cluster_id apply.

Path parameters

NameTypeDescription
cluster_idUUIDCluster identifier.

Query parameters

NameTypeDefaultAllowed valuesDescription
limitinteger1001..500Page size.
cursorstring(none)(any)Opaque pagination token.
include_totalbooleanfalsetrue, falseInclude meta.pagination.total_count.
sortstringcostcost, idcost puts the highest run rate first. id sorts by node UID, then cluster ID, an order that holds while you walk every page. See Sort policy.
node_groupstring (csv)(none)(any)Filter by node-group label value.
instance_typestring (csv)(none)(any)Filter by cloud instance type.
zonestring (csv)(none)(any)Filter by availability zone.
is_spotboolean(none)true, falseSpot vs on-demand.
is_readyboolean(none)true, falseKubernetes Ready condition.
architecturestring (csv)(none)amd64, arm64CPU architecture.
capacity_typestring (csv)(none)on-demand, spot, reserved, karpenterPricing capacity bucket.

Example request

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/clusters/c1a2b3c4-d5e6-7890-abcd-ef1234567890/nodes?is_spot=true&limit=100"

Example response

Returns an array of Node objects scoped to the path cluster. Same shape as the cross-cluster list above — metadata.cluster.id will match the path cluster_id on every row, and meta.pagination follows the same cursor rules.

json
1{
2  "data": [
3    {
4      "id": "n3c4d5e6-f7a8-9012-cdef-123456789012",
5      "kind": "Node",
6      "metadata": { "name": "ip-10-0-22-91.eu-west-1.compute.internal", "instance_type": "m5.4xlarge", "is_spot": true, "capacity_type": "spot", "availability_zone": "eu-west-1c", "...": "..." },
7      "capacity": { "...": "..." },
8      "utilization": { "...": "..." },
9      "cost": { "current_run_rate_hourly": { "amount": "0.2984", "currency": "USD" }, "on_demand_equivalent_hourly": { "amount": "0.9920", "currency": "USD" }, "pricing_source": "aws-pricing-api", "last_updated_at": "2026-05-21T10:29:51Z" }
10    }
11  ],
12  "meta": {
13    "request_id": "0196f1c2-b5f2-7b3d-aba3-56257c8bc99e",
14    "applied_at": "2026-05-21T10:31:15Z",
15    "pagination": { "has_more": false, "limit": 100 }
16  }
17}

For the complete field list, see the canonical example in List nodes (cross-cluster) or the OpenAPI spec.

Common errors

HTTPerror.codeWhen
400INVALID_CLUSTER_IDcluster_id is not a valid UUID.
401UNAUTHORIZEDMissing or invalid Bearer token.
403CLUSTER_ACCESS_DENIEDToken does not include this cluster in its allowlist.
404CLUSTER_NOT_FOUNDNo cluster with this ID exists in your organization.
410CURSOR_EXPIREDCursor older than 24h or filter set changed.
422INVALID_COST_MODE?cost_mode= was supplied.
422VALIDATION_ERRORBad filter value.
429RATE_LIMITEDPer-key quota exceeded.

The cluster is checked before the list is read; see Routes under a cluster for the order of the checks.

Get node by UID

GET /v1/nodes/{node_uid}

Required scope: nodes:read

Fetch a single node by its Kubernetes metadata.uid. The uid is stable across kubelet restarts and survives the node's full lifecycle; names like ip-10-0-12-34.eu-west-1.compute.internal change when the underlying instance is replaced. Pod responses surface the uid as metadata.node.id; recommendations surface it as resource_uid.

A UID is unique within a cluster, not across clusters: a cluster registered twice holds two copies of every node. Without cluster_id, the lookup searches every cluster the key can read. If more than one of them holds the UID, the request returns 422 VALIDATION_ERROR and lists the candidate clusters; retry with one of them as cluster_id.

Path parameters

NameTypeDescription
node_uidUUIDThe node's Kubernetes metadata.uid.

Query parameters

NameTypeDefaultAllowed valuesDescription
cluster_idUUID(none)One UUIDLook the UID up in this cluster only. Required when the UID exists in more than one of your clusters.

Example request

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/nodes/n1a2b3c4-d5e6-7890-abcd-ef0987654321"

Example response

Returns a single Node object. Same shape as one element of the List nodes (cross-cluster) response above, wrapped directly under data (no array, no pagination in meta).

json
1{
2  "data": {
3    "id": "n1a2b3c4-d5e6-7890-abcd-ef0987654321",
4    "kind": "Node",
5    "metadata": { "name": "ip-10-0-12-34.eu-west-1.compute.internal", "instance_type": "m5.2xlarge", "is_spot": false, "capacity_type": "on-demand", "availability_zone": "eu-west-1a", "...": "..." },
6    "capacity": { "...": "..." },
7    "utilization": { "...": "..." },
8    "cost": { "current_run_rate_hourly": { "amount": "0.4960", "currency": "USD" }, "on_demand_equivalent_hourly": { "amount": "0.4960", "currency": "USD" }, "pricing_source": "aws-pricing-api", "last_updated_at": "2026-05-21T10:29:48Z" }
9  },
10  "meta": {
11    "request_id": "0196f1c2-f327-79b2-b9d9-31571ca91c72",
12    "applied_at": "2026-05-21T10:31:20Z"
13  }
14}

For the complete field list, see the canonical example in List nodes (cross-cluster) or the OpenAPI spec.

Common errors

HTTPerror.codeWhen
400BAD_REQUESTnode_uid is not a valid UUID.
400INVALID_CLUSTER_IDcluster_id is not a valid UUID.
401UNAUTHORIZEDMissing or invalid Bearer token.
403FORBIDDENToken lacks the nodes:read scope.
403CLUSTER_ACCESS_DENIEDcluster_id names a cluster outside the key's allow-list.
404NODE_NOT_FOUNDNo node with that uid in the clusters the key can read (or in cluster_id, when given).
422VALIDATION_ERRORThe uid exists in more than one of your clusters and cluster_id was not given. details[0].reason is ambiguous_node_uid and details[0].allowed lists the cluster IDs to choose from.
422INVALID_COST_MODE?cost_mode= was supplied.
429RATE_LIMITEDPer-key quota exceeded.

See also

  • Node Groups: group-level aggregates over the nodes returned here (spot percentage, instance-type mix, group savings).
  • Clusters: the parent cluster identified by metadata.cluster.id on every node.
  • Workloads: list workloads, then call /pods to see which nodes their pods land on.
  • Recommendations: workload_rightsizing findings whose target pods land on these nodes.
  • Cost Modes: why nodes reject ?cost_mode= and which endpoints accept it.