API Reference
Cost Trends
Cost over time at hourly, daily, weekly or monthly granularity: five scope-specific endpoints that share one query model and one response shape.
Last updated
Cost-trend endpoints return time-series cost data for one resource scope: cluster, namespace, workload, node-group, or the whole organization. Five endpoints, a common parameter set (the node-group endpoint omits cost_mode — see exception), one response shape (CostTrendSeries).
Endpoints
| Scope | Endpoint | Required scope | cost_mode |
|---|---|---|---|
| Cluster | GET /v1/clusters/{cluster_id}/cost-trend | clusters:read | default fully_loaded |
| Namespace | GET /v1/clusters/{cluster_id}/namespaces/{namespace}/cost-trend | namespaces:read | default workload_only |
| Workload | GET /v1/clusters/{cluster_id}/workloads/by-uid/{workload_uid}/cost-trend | workloads:read | default workload_only |
| Node-group | GET /v1/clusters/{cluster_id}/node-groups/{name}/cost-trend | nodes:read | rejected (422 INVALID_COST_MODE) |
| Organization | GET /v1/organizations/dashboard/cost-trend | organization:read | default fully_loaded |
Path-parameter notes:
cluster_id,workload_uidare UUIDs.namespaceis the human-readable Kubernetes namespace name (notmetadata.uid).name(node-group) is thenode_grouplabel value. URL-encode characters such as:and,.
Query parameters
Four of the five endpoints share the same parameter set. The node-group endpoint accepts the same parameters except cost_mode — see the note below.
| Parameter | Required | Type | Default | Description |
|---|---|---|---|---|
start | yes | integer (unix epoch seconds, UTC) | — | Window start. |
end | yes | integer (unix epoch seconds, UTC) | — | Window end. Must be greater than start. Window must not exceed 5 years. |
type | no | enum | run_rate | run_rate: each bucket's burn rate projected to a full month. breakdown: actual cost summed per bucket. |
granularity | no | enum | auto | auto, hourly, daily, weekly, monthly. See granularity rules. |
cost_mode | no | enum | scope-dependent (table above) | fully_loaded or workload_only. Not accepted on the node-group endpoint — see node-group exception. |
basis | no | enum | legacy | legacy or all. See Cost basis. |
Node-group cost_mode exception
The node-group cost-trend endpoint rejects ?cost_mode= with 422 INVALID_COST_MODE, even when the value is fully_loaded or workload_only. Nodes carry a single physical cloud bill, so a node-group aggregate (the union of nodes sharing a node_group label) is mode-invariant. meta.cost_mode is omitted from the response.
This matches the rejection rule on the node-group listing and detail endpoints — see Cost Modes.
Granularity rules
| Granularity | Behavior |
|---|---|
auto (default) | Resolves to hourly for windows up to 14 days (inclusive) when hourly data answers the request exactly (see below), otherwise daily. The resolved value appears in data.granularity. |
hourly | Capped at 60-day windows. Requests with a larger window return 422 VALIDATION_ERROR. |
daily, weekly, monthly | No window cap below the 5-year ceiling. |
Hourly data answers a request exactly only when all of these hold:
type=run_rate(the default).basis=legacy(the default).- On the cluster and organization endpoints,
cost_mode=fully_loaded(the default). The namespace and workload endpoints serve hourly in both modes.
Asking for granularity=hourly outside these cases returns 422 VALIDATION_ERROR with details[0].field set to granularity; auto uses daily for them at any window length. So a total never changes because a window crossed the 14-day line.
Response
1{
2 "data": {
3 "kind": "CostTrend",
4 "scope": "cluster",
5 "scope_ref": {
6 "cluster_id": "c1a2b3c4-d5e6-7890-abcd-ef1234567890"
7 },
8 "start": "2026-05-01T00:00:00Z",
9 "end": "2026-05-08T00:00:00Z",
10 "granularity": "hourly",
11 "type": "run_rate",
12 "points": [
13 {
14 "bucket_start": "2026-05-01T00:00:00Z",
15 "total_cost": { "amount": "12.4700", "currency": "USD" }
16 },
17 {
18 "bucket_start": "2026-05-01T01:00:00Z",
19 "total_cost": { "amount": "12.5100", "currency": "USD" }
20 }
21 ]
22 },
23 "meta": {
24 "request_id": "0196f1c2-c994-7705-b234-4b214a91a07f",
25 "applied_at": "2026-05-21T10:30:00Z",
26 "cost_mode": "fully_loaded"
27 }
28}Top-level fields
| Field | Type | Description |
|---|---|---|
kind | string | Always "CostTrend". |
scope | enum | cluster, namespace, workload, node-group, or organization. Matches the endpoint called. |
scope_ref | object | Identifies the entity. Field presence varies by scope (see scope_ref shape). Omitted for organization. |
start | string | RFC 3339 UTC anchor of the window start. |
end | string | RFC 3339 UTC anchor of the window end. |
granularity | enum | Post-resolution value. Always one of hourly, daily, weekly, monthly. Never auto. |
type | enum | Echoes the requested type (run_rate or breakdown). |
points | array | One entry per bucket. Always an array — empty windows serialize as [], never null. |
excluded_cluster_ids | string[] | Present only on organization scope. The clusters left out of the series because they have not reported for 15 minutes, sorted. [] when none. |
scope_ref shape
| Scope | Fields |
|---|---|
cluster | cluster_id |
namespace | cluster_id, namespace |
workload | cluster_id, workload_uid |
node-group | cluster_id, node_group |
organization | omitted |
Bucket fields
| Field | Type | Description |
|---|---|---|
bucket_start | string | RFC 3339 UTC anchor of the bucket (start of hour, day, week, or month). |
total_cost | Money | {amount, currency}. amount is a decimal string. |
components, unallocated, basis, partial | The bucket's cost block fields. |
Empty-result behavior
A key that may read no cluster at all gets 403 CLUSTER_ACCESS_DENIED with details[0].reason set to no_cluster_in_scope, on every endpoint including the organization one. The cluster, namespace, workload and node-group endpoints check the path's cluster first, in the order described in Routes under a cluster. A window with no cost returns 200 OK with points: [].
Errors
| HTTP | error.code | Cause |
|---|---|---|
| 400 | INVALID_CLUSTER_ID | cluster_id is not a valid UUID. |
| 401 | UNAUTHORIZED | Missing or invalid Bearer token. |
| 403 | FORBIDDEN | API key lacks the scope this endpoint requires. |
| 403 | CLUSTER_ACCESS_DENIED | API key cannot reach the cluster in the path, or may read no cluster at all (no_cluster_in_scope). |
| 404 | CLUSTER_NOT_FOUND | No cluster with the path's ID exists in your organization. |
| 404 | NAMESPACE_NOT_FOUND / WORKLOAD_NOT_FOUND / NODE_GROUP_NOT_FOUND | Path-bound resource does not exist in the cluster. |
| 422 | VALIDATION_ERROR | start or end missing (details[0] is { "field": "start", "reason": "required" }), workload_uid is not a valid UUID, start/end is not a numeric epoch timestamp, end ≤ start, window > 5 years, granularity=hourly with a window > 60 days, granularity=hourly on a request hourly data cannot answer exactly (see granularity rules), or an unknown enum value. |
| 422 | INVALID_COST_MODE | cost_mode is not fully_loaded or workload_only, OR cost_mode was supplied to the node-group endpoint (which rejects the parameter — see exception). |
| 429 | RATE_LIMITED | Per-key quota exceeded. Honor Retry-After. |
| 500 | INTERNAL_ERROR | Unhandled server error. |
| 504 | UPSTREAM_TIMEOUT | The window was too expensive to compute in time. Narrow start/end or use a coarser granularity, then retry. |
See Error Handling for the full catalog and retry guidance.
Examples
Hourly run-rate for one cluster, last seven days
END=$(date -u +%s)
START=$(( END - 7*86400 )) # portable on macOS and Linux
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/clusters/c1a2b3c4-d5e6-7890-abcd-ef1234567890/cost-trend?start=$START&end=$END&type=run_rate&granularity=hourly"Monthly breakdown for an organization, last year
END=$(date -u +%s)
START=$(( END - 365*86400 ))
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/organizations/dashboard/cost-trend?start=$START&end=$END&type=breakdown&granularity=monthly"Workload trend with explicit cost mode
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/clusters/c1a2b3c4-d5e6-7890-abcd-ef1234567890/workloads/by-uid/b9f1a342-7c5e-4d8a-9e2b-1234567890ab/cost-trend?start=1748736000&end=1749340800&granularity=daily&cost_mode=fully_loaded"See also
- API Overview: base URL, envelope shape, the full endpoint index.
- Cost Modes: the
fully_loadedvsworkload_onlycontract and per-scope defaults. - Permission Scopes: the scopes that gate each cost-trend endpoint.
- Error Handling: the full error code catalog and recommended retry behavior.