API Reference
Cost Trends
Time-series cost data at hourly, daily, weekly, or monthly granularity. Five scope-specific endpoints, one shared query model, and the CostTrendSeries response shape.
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. |
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 ≤ 14 days (inclusive), 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. |
type=breakdown rejects granularity=hourly. Pair breakdown with daily or coarser.
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 "excluded_cluster_ids": []
23 },
24 "meta": {
25 "request_id": "req_01J5...",
26 "applied_at": "2026-05-21T10:30:00Z",
27 "cost_mode": "fully_loaded"
28 }
29}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[] | Populated only on organization scope, listing clusters that are not included in the response (for example, clusters the API key cannot access). |
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. |
Empty-result behavior
The organization endpoint returns 200 OK with points: [] and excluded_cluster_ids: [] when the API key has an empty allowed-cluster list. It does not return 403. Resource-scoped endpoints (cluster, namespace, workload, node-group) return 403 CLUSTER_ACCESS_DENIED if the path-bound cluster is outside the key's allow-list.
Errors
| HTTP | error.code | Cause |
|---|---|---|
| 400 | BAD_REQUEST | Missing start or end, non-integer epoch, malformed UUID. |
| 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. |
| 404 | CLUSTER_NOT_FOUND / NAMESPACE_NOT_FOUND / WORKLOAD_NOT_FOUND / NODE_GROUP_NOT_FOUND | Path-bound resource does not exist in the tenant. |
| 422 | VALIDATION_ERROR | end ≤ start, window > 5 years, granularity=hourly with a window > 60 days, type=breakdown with granularity=hourly, 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. |
| 503 | SERVICE_UNAVAILABLE | A backend dependency was unavailable. Retry with backoff. |
See Error Handling for the full catalog and retry guidance.
Examples
Hourly run-rate for one cluster, last seven days
START=$(date -u -d '7 days ago' +%s)
END=$(date -u +%s)
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
START=$(date -u -d '12 months ago' +%s)
END=$(date -u +%s)
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/01J5K3V0Q7Y4XR8A2B3C5D7E9F/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.