API Reference
Cost Explorer
POST /v1/cost-explorer/query: aggregated cost rows with filters, grouping, and KPI summary. Body schema, filter DSL, response shape, and errors.
The Cost Explorer endpoint runs aggregated cost queries against your tenant's billable resources. One endpoint, one method, one body schema, one paginated response.
Endpoint
POST /v1/cost-explorer/query| Required scope | cost_explorer:read |
| Pagination | Offset-based (page / per_page) — distinct from the cursor pagination used elsewhere. |
| Cost mode | Accepted. Default fully_loaded. |
| Body cap | 1 MiB. Exceeding it returns 413 with error.code = BAD_REQUEST. |
| Cluster scoping | Results are scoped to clusters your API key is authorized to access. A request that names only non-permitted clusters returns an empty result, not an error. |
Request body
All fields are optional. Defaults below apply when a field is omitted.
| Field | Type | Default | Description |
|---|---|---|---|
group_by | enum | workload | One of workload, namespace, controller_kind, pod, container, deployment, statefulset, daemonset, node, instance_type. The cluster axis is not exposed on the public API — use /v1/organization/dashboard for fleet-wide cost breakdown. |
cost_mode | enum | fully_loaded | fully_loaded or workload_only. See Cost Modes. |
start_date | string (YYYY-MM-DD) | — | Inclusive. |
end_date | string (YYYY-MM-DD) | — | Inclusive. |
page | integer | 1 | 1-indexed. |
per_page | integer | 50 | Capped at 500 for normal requests, 10000 when export=true. |
sort_by | string | totalCost | Any field on a result row (e.g. workloadName, co2Kg). |
sort_order | enum | desc | asc or desc. |
search | string | — | Substring match against the grouping dimension (workload name, namespace, etc.). |
view_mode | enum | detail | detail (per-resource rows) or grouped (aggregated rows). |
filter_expression | object | — | See Filter expression. |
cluster_ids | string[] | — | UUIDs. Empty array means "all clusters the API key can access". |
projected | boolean | false | When true, scales partial-collection days up to a full 24-hour equivalent. When false, returns the observed cost (matches cloud billing). |
export | boolean | false | Raises the per_page cap to 10,000. UI clients should leave this false. |
granularity | enum | daily | daily, weekly, or monthly. Time-bucket for daily-breakdown outputs. |
Filter expression
A filter expression is a set of groups combined with AND or OR. Each group holds one or more field filters and one or more label filters; predicates within a group are always combined with AND.
1{
2 "filter_expression": {
3 "group_operator": "AND",
4 "groups": [
5 {
6 "filters": [
7 { "field": "namespace", "operator": "in", "values": ["prod", "staging"] }
8 ],
9 "label_filters": [
10 { "key": "team", "operator": "eq", "values": ["platform"] }
11 ]
12 }
13 ]
14 }
15}| Filter type | Field | Operators |
|---|---|---|
filters[] | field (any indexed dimension), operator, values[] | eq, ne, in, not_in, contains |
label_filters[] | key (label name), operator, values[] | eq, ne, exists, not_exists (values omitted for exists/not_exists) |
group_operator | — | AND or OR (between groups). |
Response
1{
2 "data": {
3 "items": [
4 {
5 "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
6 "workloadName": "checkout-api",
7 "workloadKind": "Deployment",
8 "namespace": "prod",
9 "cluster": "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
10 "clusterName": "prod-us-east",
11 "workloadUid": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
12 "pods": 12,
13 "totalCost": { "amount": "412.5300", "currency": "USD" },
14 "co2Kg": 7.4
15 }
16 ],
17 "summary": {
18 "periodCost": 412.53,
19 "previousPeriodCost": 387.10,
20 "changePercentage": 6.57,
21 "scannedResources": 248,
22 "queryTimeMs": 142,
23 "dataCompleteness": 0.99,
24 "topNamespace": "prod",
25 "topNamespaceCost": 287.42
26 },
27 "pagination": {
28 "page": 1,
29 "perPage": 50,
30 "totalCount": 248,
31 "totalPages": 5
32 },
33 "excludedClusterIds": []
34 },
35 "meta": {
36 "request_id": "req_01J5...",
37 "applied_at": "2026-05-21T10:30:00Z",
38 "cost_mode": "fully_loaded"
39 }
40}Item fields
| Field | Type | Description |
|---|---|---|
id | string | Stable row identifier within the response. |
workloadName | string | Resource name at the grouping dimension. |
workloadKind | string | Resource kind (Deployment, StatefulSet, etc.). |
namespace | string | Kubernetes namespace. |
cluster | string | Cluster UUID. |
clusterName | string | Human-readable cluster name. |
workloadUid | string | Kubernetes metadata.uid. |
nodeUid | string | Optional. Node UID; populated when the grouping dimension exposes it (e.g. group_by=pod, group_by=node). |
podUid | string | Optional. Pod UID; populated when the grouping dimension exposes it (e.g. group_by=pod, group_by=container). |
pods | integer | Number of pods contributing to the row. |
totalCost | Money | {amount, currency}. amount is a decimal string. |
co2Kg | number | Estimated CO₂ emissions in kilograms for the period. |
Summary fields
| Field | Type | Description |
|---|---|---|
periodCost | number | Total cost for the requested window. |
previousPeriodCost | number | Total cost for the equivalent prior window. |
changePercentage | number | (periodCost − previousPeriodCost) / previousPeriodCost × 100. |
scannedResources | integer | Distinct resources touched by the query. |
queryTimeMs | integer | Server-side query duration. |
dataCompleteness | number | [0,1] ratio of observed to expected data points for the window. Values below 0.98 indicate incomplete data for the period. |
topNamespace | string | Namespace contributing the most cost. |
topNamespaceCost | number | Cost for topNamespace. |
Top-level response fields
items, summary, and pagination are documented above. The response also includes:
| Field | Type | Description |
|---|---|---|
excludedClusterIds | string[] | Cluster UUIDs that were excluded from the aggregation (for example, clusters with no usage data). Clusters outside the API key's access do not appear in this list. Empty when no clusters were excluded. Sits at the response root, not inside summary. |
Errors
| HTTP | error.code | Cause |
|---|---|---|
| 400 | BAD_REQUEST | Malformed body, unknown filter operator, unparseable date. |
| 401 | UNAUTHORIZED | Missing or invalid Bearer token. |
| 403 | FORBIDDEN | API key lacks cost_explorer:read. |
| 413 | BAD_REQUEST | Body exceeded the 1 MiB cap. |
| 422 | VALIDATION_ERROR | group_by, cost_mode, sort_order, view_mode, granularity, or operator value not in the allowed set. |
| 422 | INVALID_COST_MODE | cost_mode is not fully_loaded or workload_only. |
| 429 | RATE_LIMITED | Per-key quota exceeded. Honor Retry-After. |
| 500 | INTERNAL_ERROR | Unhandled server error. |
| 502 | UPSTREAM_UNAVAILABLE | An upstream service returned an error or was unreachable. |
| 504 | UPSTREAM_TIMEOUT | Upstream call exceeded the 60s deadline. |
See Error Handling for the full catalog and retry guidance.
Example
Group spend by namespace across two clusters for the first week of May, sorted by total cost descending:
1curl -X POST \
2 -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "group_by": "namespace",
6 "cost_mode": "fully_loaded",
7 "start_date": "2026-05-01",
8 "end_date": "2026-05-07",
9 "page": 1,
10 "per_page": 100,
11 "sort_by": "totalCost",
12 "sort_order": "desc",
13 "cluster_ids": [
14 "c1a2b3c4-d5e6-7890-abcd-ef1234567890",
15 "c2b3c4d5-e6f7-8901-bcde-f23456789012"
16 ]
17 }' \
18 "https://public-api.kubeadapt.io/v1/cost-explorer/query"See also
- API Overview: base URL, envelope shape, the full endpoint index.
- Permission Scopes: the
cost_explorer:readscope and the cluster ACL model. - Cost Modes: the
fully_loadedvsworkload_onlycontract. - Error Handling: the full error code catalog including
UPSTREAM_UNAVAILABLEandUPSTREAM_TIMEOUT.