Skip to content

API Reference

Exports

Download a FOCUS 1.4 cost export as CSV, JSON Lines or Parquet, and read the schema that describes it. Parameters, limits and errors.


The export endpoints return your cost data as a FOCUS 1.4 Cost and Usage file, the same file the Kubeadapt dashboard produces. Use them to load Kubernetes cost into a data warehouse or a FinOps tool that reads FOCUS.

Endpoints

EndpointReturnsRequired scope
GET /v1/exports/focusThe export file, streamedcost_explorer:read
GET /v1/exports/focus/schemaThe FOCUS metadata object for one export configuration, as JSON in the standard envelopecost_explorer:read

Export a window

GET /v1/exports/focus

Query parameters

NameRequiredDefaultAllowed valuesDescription
fromyesYYYY-MM-DD (UTC)First day of the window, inclusive.
toyesYYYY-MM-DD (UTC)The day after the last day of the window (exclusive). The window can be at most 3,660 days.
formatnocsvcsv, jsonl, parquetFile format.
grainnoworkloadworkload, namespaceOne row per workload or per namespace.
idlenounallocatedunallocated, apportionedunallocated keeps idle capacity on its own rows; apportioned spreads it across the rows that used the node.
columnsnoallcomma-separated FOCUS column namesLimit the file to these columns. An unknown name returns 422.
cluster_idnoevery cluster the key can readUUID, repeatable or comma-separatedLimit the export to these clusters.
basisnoallallThe export always carries every cost component, so basis=legacy returns 422. See Cost basis.

Example

Export January 2026 at workload grain as CSV:

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -o kubeadapt-focus-2026-01.csv \
  "https://public-api.kubeadapt.io/v1/exports/focus?from=2026-01-01&to=2026-02-01&format=csv&grain=workload"

Check that the file is complete

The response streams, so the 200 status is sent before the first row. A 200 means the export started, not that it finished. Kubeadapt reports the outcome in HTTP trailers sent after the last row:

TrailerMeaning
X-Export-Statuscomplete, or error. error means the file is short: discard it and retry.
X-Export-Row-CountRows written to the file.
X-Export-Ledger-RowsSource rows read to produce them.

Go exposes trailers as resp.Trailer once the body has been read. If your client cannot read trailers, treat a short file as possible. If the connection ends before the trailers arrive, request a shorter window.

Headers sent before the body:

HeaderMeaning
Content-Dispositionattachment, with a file name that names the grain and window.
X-Focus-VersionThe FOCUS version the file follows.
X-Focus-Schema-IdIdentifies the column set. Matches schema_id from the schema endpoint for the same configuration.
X-Focus-Dataset-Instance-IdIdentifies the delivery scope. A later file with the same value replaces the earlier one in full.
X-Export-Partialtrue when the key's cluster allow-list left clusters out of the file.

Limits

  • 6 requests per minute per API key, on top of the 100 per minute limit. To pull more history, widen the window rather than looping over short ones.
  • Cluster scope. cluster_id is intersected with the key's cluster allow-list. A restricted key that names only clusters outside its list gets 403 CLUSTER_ACCESS_DENIED; the export is never widened to the whole tenant.

Read the schema

GET /v1/exports/focus/schema

Returns the FOCUS metadata object for one configuration: the column definitions, how corrections and delivery are handled, and what the key's cluster scope leaves out. The schema_id it returns is the one stamped on every file produced with the same configuration.

It accepts grain, idle, columns and basis with the same meaning as above. It does not read from, to or cluster_id: the schema always describes what this key can export. It does not count against the 6-per-minute export limit.

bash
curl -H "Authorization: Bearer ka_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  "https://public-api.kubeadapt.io/v1/exports/focus/schema?grain=workload&idle=unallocated"

Errors

Errors on both endpoints use the standard {data, meta, error} envelope.

HTTPerror.codeCause
400INVALID_CLUSTER_IDA cluster_id value is not a valid UUID.
401UNAUTHORIZEDMissing or invalid Bearer token.
403FORBIDDENAPI key lacks cost_explorer:read.
403CLUSTER_ACCESS_DENIEDNo requested cluster is in the key's allow-list (details[0].reason is no_cluster_in_scope).
422VALIDATION_ERRORfrom or to missing or not YYYY-MM-DD; to not after from; window longer than 3,660 days; unknown format, grain, idle or column; basis=legacy.
429RATE_LIMITEDOver the export limit or the service-wide limit. Honor Retry-After.
500INTERNAL_ERRORUnhandled server error.
502UPSTREAM_UNAVAILABLEThe export could not be produced. Retry with backoff.

See Error Handling for the full catalog.

See also