API Reference
API Overview
Base URL, envelope shape, content type, server time, rate limits, and the full endpoint index for the Kubeadapt /v1 REST API.
The Kubeadapt /v1 REST API exposes read-only access to cost, capacity, and resource data across every Kubernetes cluster connected to a tenant. Every endpoint is GET (with one exception for Cost Explorer queries), every response uses a single {data, meta, error} envelope, and every request authenticates with a Bearer API key.
Interactive surface
Two unauthenticated entry points are available before you ever mint a key:
- Swagger UI — public-api.kubeadapt.io/v1/docs. Paste a Bearer token, execute requests against your tenant in the browser.
- OpenAPI 3.1 spec —
/v1/openapi.jsonor/v1/openapi.yaml. Source of truth for the contract; feed it to an SDK generator.
Base URL
Every request goes to:
https://public-api.kubeadapt.ioThe path prefix /v1 carries the version. Every endpoint in this reference starts with /v1 (so GET /v1/clusters, GET /v1/organization, and so on).
The universal envelope
Every response uses the same top-level wrapper:
{
"data": <resource | array of resources>,
"meta": { "request_id": "...", "applied_at": "..." },
"error": { "code": "...", "message": "...", "details": [...] }
}- On success, the
errorkey is omitted entirely (not"error": null). Branch onresponse.error == nullas the canonical success check. - On error,
datais explicitlynullanderrorcarriescode,message, and an optionaldetailsarray. See Error Handling for the full code catalog. meta.request_idandmeta.applied_atare present on every response. Includerequest_idwhen contacting support.
A success body:
1{
2 "data": {
3 "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
4 "name": "Acme Platform",
5 "currency": "USD",
6 "counts": {
7 "clusters_total": 14,
8 "connected_clusters": 12
9 }
10 },
11 "meta": {
12 "request_id": "req_01J5K3V0Q7Y4XR8A2B3C5D7E9F",
13 "applied_at": "2026-05-21T10:30:00Z"
14 }
15}Content type
application/json only. The API does not speak XML, protobuf, or any streaming protocol. Every request body (when one exists) is JSON; every response body is JSON. There are no file downloads, no chunked transfers, no Server-Sent Events.
Set Accept: application/json if your HTTP client requires an explicit Accept header. Without it, the API still responds with JSON.
Server time
All timestamps are UTC, formatted as RFC 3339 with seconds precision and a Z suffix:
2026-05-21T10:30:00ZEvery field ending in _at follows this format: applied_at, created_at, updated_at, last_seen_at, and the rest. No millisecond precision, no +00:00 offset, no timezone names. If your client reads applied_at and compares it to time.Now(), do it in UTC.
Dates without a time component (in query parameters, for instance) are YYYY-MM-DD. Date ranges are inclusive at the start and exclusive at the end.
Rate limits
The default is 100 requests per minute per API key. Exceeding the quota returns 429 RATE_LIMITED with a Retry-After header (seconds). If rate-limit enforcement is temporarily unavailable, the API returns 503 RATE_LIMIT_UNAVAILABLE — back off and retry the same way.
For the full envelope shapes and retry policy, see Error Handling. For a higher limit on a specific integration, contact support@kubeadapt.io.
What's NOT here
Things the /v1 API explicitly does not do, listed so you don't spend time looking:
- No write operations. Every endpoint is
GET. There is noPOST /v1/recommendations/{id}/apply, noPUT /v1/teams/{id}, noDELETEanywhere. - No webhooks. The API does not push events to your endpoint. Poll the resources you care about, or use the Smart Alerting channels (Slack, email, webhook) configured in the dashboard.
- No streaming. No long-polling, no Server-Sent Events, no WebSockets. List endpoints paginate with cursors.
- No GraphQL. Plain REST. If you want a single round-trip with joined data, use the
dashboardendpoints (e.g.,/v1/organization/dashboard), which embed top-N summaries. - No OpenTelemetry receiver. Kubeadapt does not accept OTLP traces or metrics. The in-cluster agent is the only data source. See How Kubeadapt works.
- No SDK shipping in this release. The OpenAPI spec is public; generate a client with
openapi-generator-cliagainst/v1/openapi.yaml.
Endpoint index
One row per resource family. Every endpoint requires a Bearer API key (see Authentication) and a scope (see Permission Scopes). The Paginated column refers to the family's list endpoints. The cost_mode column describes how the family handles the ?cost_mode= query parameter (see Cost Modes).
| Family | Scope | Paginated | cost_mode |
|---|---|---|---|
| Organization | organization:read | no | accepts on /dashboard, rejects on snapshot |
| Clusters | clusters:read | yes (cursor) | REJECTS |
| Namespaces | namespaces:read | yes (cursor) | accepts |
| Workloads | workloads:read | yes (cursor) | accepts |
| Nodes | nodes:read | yes (cursor) | REJECTS |
| Node Groups | nodes:read | no | REJECTS |
| Recommendations | recommendations:read | yes (cursor) | REJECTS |
| Teams | teams:read | yes (cursor) | accepts (live) |
| Departments | departments:read | yes (cursor) | accepts (live) |
| Cost Explorer | cost_explorer:read | yes (offset) | accepts |
| Cost Trends | per-resource scope | n/a (series) | accepts (except node-group, which REJECTS) |
| Discovery | unauthenticated | n/a | n/a |
Notes on the table:
- Node Groups uses
nodes:read— the two families share authorization. - Cost Explorer uses offset pagination (
page/per_page), not cursor pagination. Every other paginated family uses cursors. - Cost Trends scope depends on the path: cluster →
clusters:read, namespace →namespaces:read, workload →workloads:read, node-group →nodes:read, organization-dashboard →organization:read. cost_modebehavior — on Namespaces and Workloads, the response echoes the requested mode but both values currently return the sameamount. On Teams, Departments, the Organization Dashboard, Cost Trends (cluster, namespace, workload, organization), and Cost Explorer, the modes return different numbers. The node-group cost-trend endpoint rejects?cost_mode=(one physical bill per node).- REJECTS means the endpoint returns
422 INVALID_COST_MODEif you pass?cost_mode=. The Organization snapshot at/v1/organizationrejects it (the org-level bill is one physical number); the Organization Dashboard at/v1/organization/dashboardaccepts it. - Discovery covers
/v1/openapi.*and/v1/docs. These do not require a Bearer token.
First request
Fetch the organization snapshot to confirm the key works end-to-end:
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
"https://public-api.kubeadapt.io/v1/organization"A 200 OK returns the tenant snapshot — full schema in the Organization reference. A 401 UNAUTHORIZED means the key was not accepted; a 403 FORBIDDEN means the key lacks the organization:read scope. See Authentication for the 401 vs 403 distinction.
See also
- Authentication: the Bearer token format, key minting, rotation, and 401 vs 403.
- Permission Scopes: the nine read scopes and which endpoints they cover.
- Pagination & Filtering: cursor semantics,
limit,include_total, and filter operators. - Error Handling: the full error code catalog and recommended retry behavior.
- Cost Modes:
fully_loadedvsworkload_only, when each is accepted, and how the response echoes the mode. - Organization: the full snapshot and dashboard schemas, plus the cost-mode rejection on the snapshot endpoint.