Skip to content

API Reference

Base URL: http://localhost:8080 (configurable via api.host and api.port)

All endpoints except /health are prefixed with /api/v1.

General behavior

  • Authentication: None built-in. Use a reverse proxy for auth.
  • CORS: Configurable via api.enable_cors and api.cors_origins. Allowed methods: GET, POST, PATCH, DELETE.
  • Request timeout: Requests exceeding api.request_timeout_seconds (default 30, max 300) return HTTP 504.
  • Content type: JSON for all endpoints except export (CSV).

Pagination

List endpoints accept:

Parameter Type Default Constraints
page int 1 >= 1
page_size int 100 1–1000

Response includes: items, total, page, page_size, pages.

Date range defaults

When start_date / end_date are omitted, the API uses the tenant's configured lookback window.

Error responses

Status Meaning
400 Invalid parameters (bad filter, unknown column, etc.)
404 Tenant or resource not found
409 Pipeline already running (trigger endpoint)
504 Request timeout

Health & Readiness

GET /health

Lightweight liveness check.

Response: {"status": "ok", "version": "<version>"}

GET /api/v1/readiness

Per-tenant readiness with pipeline state. TTL-cached for 2 seconds.

Response fields:

Field Type Description
status string ready, initializing, no_data, or error
version string Package version
mode string Run mode (api, worker, both)
tenants list Per-tenant status (see below)

Per-tenant fields: tenant_name, tables_ready, has_data, pipeline_running, pipeline_stage, pipeline_current_date, last_run_status, last_run_at, permanent_failure, topic_attribution_status, topic_attribution_error.

topic_attribution_status is one of "disabled" | "enabled" | "config_error". topic_attribution_error is a string describing the validation failure when topic_attribution_status is "config_error", otherwise null.


Tenants

GET /api/v1/tenants

List all configured tenants with summary pipeline state.

Response fields per tenant: tenant_name, tenant_id, ecosystem, dates_pending, dates_calculated, last_calculated_date, topic_attribution_status, topic_attribution_error.

topic_attribution_status is one of "disabled" | "enabled" | "config_error". See GET /api/v1/readiness above for field semantics.

GET /api/v1/tenants/{tenant_name}/status

Detailed per-date pipeline state for a tenant.

Parameter Type Required Description
start_date date no Filter from this date
end_date date no Filter to this date

Response: {tenant_name, tenant_id, ecosystem, topic_attribution_status, topic_attribution_error, states} where states is a list of {tracking_date, billing_gathered, resources_gathered, chargeback_calculated, topic_overlay_gathered, topic_attribution_calculated} per date. The topic_overlay_gathered and topic_attribution_calculated fields are false when topic attribution is disabled or in config_error state.


Billing

GET /api/v1/tenants/{tenant_name}/billing

List raw billing line items. Paginated.

Parameter Type Required Description
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries (e.g. America/Denver). Defaults to UTC.
product_type string no Filter by product type
resource_id string no Filter by resource

Response fields per item: ecosystem, tenant_id, timestamp, resource_id, product_category, product_type, quantity, unit_price, total_cost, currency, granularity, metadata.


Chargebacks

GET /api/v1/tenants/{tenant_name}/chargebacks

List allocated chargeback rows. Paginated.

Parameter Type Required Description
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries (e.g. America/Denver). Defaults to UTC.
identity_id string no Filter by identity
product_type string no Filter by product type
resource_id string no Filter by resource
cost_type string no Filter by cost type
tag_key string no Filter by tag key
tag_value string no Filter by tag value (requires tag_key)

Response fields per item: dimension_id, ecosystem, tenant_id, timestamp, resource_id, product_category, product_type, identity_id, cost_type, amount, allocation_method, allocation_detail, tags, metadata.

tags is a dict[str, str] mapping tag keys to tag values (e.g. {"team": "platform", "env": "prod"}). Tags are resolved at query time from the linked resource or identity.

GET /api/v1/tenants/{tenant_name}/chargebacks/{dimension_id}

Get a single chargeback dimension.

Response: Dimension fields (tags not resolved at this level — use /chargebacks list endpoint for tag-enriched rows).

GET /api/v1/tenants/{tenant_name}/chargebacks/dates

List all distinct dates with chargeback data.

Response: {"dates": ["2026-01-01", "2026-01-02", ...]}

GET /api/v1/tenants/{tenant_name}/chargebacks/allocation-issues

Aggregated view of failed or problematic allocations. Paginated. Same filters as chargebacks list.

Response fields per item: ecosystem, resource_id, product_type, identity_id, allocation_detail, row_count, usage_cost, shared_cost, total_cost.


Aggregation

GET /api/v1/tenants/{tenant_name}/chargebacks/aggregate

Multi-dimensional aggregation with time bucketing. Returns up to 10,000 buckets.

Parameter Type Default Description
group_by list[string] ["identity_id"] Columns to group by (repeatable)
time_bucket string day hour, day, week, or month
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries (e.g. America/Denver). Defaults to UTC.
identity_id string no Filter by identity
product_type string no Filter by product type
resource_id string no Filter by resource
cost_type string no Filter by cost type

Valid group_by columns: identity_id, resource_id, product_type, product_category, cost_type, allocation_method, environment_id.

Response:

{
  "buckets": [
    {
      "dimensions": {"identity_id": "sa-12345"},
      "time_bucket": "2026-01-01",
      "total_amount": "150.00",
      "usage_amount": "120.00",
      "shared_amount": "30.00",
      "row_count": 42
    }
  ],
  "total_amount": "150.00",
  "usage_amount": "120.00",
  "shared_amount": "30.00",
  "total_rows": 42
}

usage_amount is cost attributed by actual usage metrics. shared_amount is cost split evenly.


Resources

GET /api/v1/tenants/{tenant_name}/resources

List discovered resources. Paginated. Supports three temporal query modes:

Parameter Type Default Description
resource_type string Filter by type
status string Filter by status (active or deleted)
active_at datetime Resources active at this point in time
period_start + period_end datetime Resources active during this period
search string Case-insensitive substring match on resource_id and display_name
sort_by string Column to sort by: resource_id, display_name, resource_type, status. Falls back to resource_id if invalid.
sort_order string asc Sort direction: asc or desc. Applied when no temporal params are set.
tag_key string Filter to resources that have this tag key
tag_value string Narrow tag_key filter to this value (requires tag_key)

search, sort_by, sort_order, tag_key, and tag_value apply only when no temporal params (active_at, period_start/period_end) are set.

If no temporal params: returns all resources. Cannot combine active_at with period_start/period_end.

Response fields per item: ecosystem, tenant_id, resource_id, resource_type, display_name, parent_id, owner_id, status, created_at, deleted_at, last_seen_at, metadata.


Identities

GET /api/v1/tenants/{tenant_name}/identities

List discovered identities. Paginated. Same temporal query modes as resources.

Parameter Type Default Description
identity_type string Filter by type
active_at datetime Identities active at this point
period_start + period_end datetime Identities active during period
search string Case-insensitive substring match on identity_id and display_name
sort_by string Column to sort by: identity_id, display_name, identity_type. Falls back to identity_id if invalid.
sort_order string asc Sort direction: asc or desc. Applied when no temporal params are set.
tag_key string Filter to identities that have this tag key
tag_value string Narrow tag_key filter to this value (requires tag_key)

search, sort_by, sort_order, tag_key, and tag_value apply only when no temporal params are set.

Response fields per item: ecosystem, tenant_id, identity_id, identity_type, display_name, created_at, deleted_at, last_seen_at, metadata.


Inventory

GET /api/v1/tenants/{tenant_name}/inventory/summary

Counts of resources and identities grouped by type.

Response: {"resource_counts": {"cluster": {"total": 3, "active": 3, "deleted": 0}}, "identity_counts": {"service_account": {"total": 12, "active": 10, "deleted": 2}}}


Tags

Tags attach to entities (resources or identities) and propagate to chargeback rows at query time. entity_type must be "resource" or "identity".

GET /api/v1/tenants/{tenant_name}/entities/{entity_type}/{entity_id}/tags

List all tags on an entity.

Response: Array of tag objects with fields tag_id, tenant_id, entity_type, entity_id, tag_key, tag_value, created_by, created_at.

POST /api/v1/tenants/{tenant_name}/entities/{entity_type}/{entity_id}/tags

Create a tag on an entity. Returns 201. Returns 409 if a tag with the same key already exists on this entity.

Body: {"tag_key": "team", "tag_value": "platform", "created_by": "admin"}

PUT /api/v1/tenants/{tenant_name}/entities/{entity_type}/{entity_id}/tags/{tag_key}

Update a tag's value.

Body: {"tag_value": "new-value"}

DELETE /api/v1/tenants/{tenant_name}/entities/{entity_type}/{entity_id}/tags/{tag_key}

Delete a tag by key. Returns 204.

GET /api/v1/tenants/{tenant_name}/tags

List all tags for a tenant. Paginated.

Parameter Type Description
entity_type string Filter by entity type ("resource" or "identity")
tag_key string Filter by tag key
page int Page number (default 1)
page_size int Page size 1–1000 (default 100)

Response: {"items": [...], "total": N, "page": 1, "page_size": 100, "pages": N}

POST /api/v1/tenants/{tenant_name}/tags/bulk

Bulk create/update tags on explicit entity IDs.

Body:

{
  "items": [
    {"entity_type": "resource", "entity_id": "cluster-1", "tag_key": "team", "tag_value": "platform"},
    {"entity_type": "identity", "entity_id": "sa-abc", "tag_key": "team", "tag_value": "data"}
  ],
  "created_by": "admin",
  "override_existing": false
}

Response: {"created_count": 2, "updated_count": 0, "skipped_count": 0}

When override_existing is true, existing tags with the same key are updated instead of skipped.

POST /api/v1/tenants/{tenant_name}/tags/bulk-by-filter

Bulk tag all unique resources/identities found in chargebacks matching the given filters. Resolves entities server-side.

Body:

{
  "start_date": "2026-01-01",
  "end_date": "2026-01-31",
  "timezone": "America/Denver",
  "identity_id": "sa-abc",
  "tag_key": "team",
  "display_name": "Platform",
  "created_by": "admin",
  "override_existing": false
}

display_name is stored as the tag value. identity_id narrows which chargebacks are scanned.

Response: {"created_count": 2, "updated_count": 0, "skipped_count": 0}


Pipeline

POST /api/v1/tenants/{tenant_name}/pipeline/run

Trigger a pipeline run for a tenant. Returns 202 (accepted).

Returns HTTP 409 if a run is already in progress. Requires both mode — API-only mode cannot trigger runs.

GET /api/v1/tenants/{tenant_name}/pipeline/status

Get latest pipeline run status.

Response:

{
  "tenant_name": "my-org",
  "is_running": false,
  "last_run": "2026-03-17T12:00:00Z",
  "last_result": {
    "dates_gathered": 5,
    "dates_calculated": 5,
    "chargeback_rows_written": 142,
    "errors": [],
    "completed_at": "2026-03-17T12:00:00Z"
  }
}

last_result is null if no completed or failed runs exist.


Export

POST /api/v1/tenants/{tenant_name}/export

Stream chargeback data as CSV. Returns text/csv with Content-Disposition: attachment.

Body:

{
  "columns": ["timestamp", "resource_id", "product_type", "identity_id", "amount"],
  "start_date": "2026-01-01",
  "end_date": "2026-01-31",
  "timezone": "America/Denver",
  "filters": {
    "identity_id": "sa-12345",
    "product_type": "KAFKA_NUM_CKU"
  }
}
Field Type Default Description
columns list[string] 9 default columns Columns to include
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries (e.g. America/Denver). Defaults to UTC.
filters dict no Key-value filters (identity_id, product_type, resource_id, cost_type)

All available columns: ecosystem, tenant_id, timestamp, resource_id, product_category, product_type, identity_id, cost_type, amount, allocation_method, allocation_detail, tags, metadata.

The tags column is serialized as key=value;key=value pairs (e.g. team=platform;env=prod).

Default columns: timestamp, resource_id, product_category, product_type, identity_id, cost_type, amount, allocation_method, tags.


Topic Attributions

Topic attribution rows are produced by the optional topic_overlay pipeline stage (Confluent Cloud only). Each row represents the cost portion attributed to one topic for one billing line item. Requires topic_attribution.enabled: true in plugin settings.

GET /api/v1/tenants/{tenant_name}/topic-attributions

List topic attribution rows. Paginated.

Parameter Type Required Description
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries. Defaults to UTC.
cluster_resource_id string no Filter by cluster (e.g. lkc-abc123)
topic_name string no Filter by topic name
product_type string no Filter by product type
attribution_method string no Filter by method (bytes_ratio, retained_bytes_ratio, even_split)
page int no Page number (default 1)
page_size int no Page size 1–1000 (default 100)

Response fields per item: dimension_id, ecosystem, tenant_id, timestamp, env_id, cluster_resource_id, topic_name, product_category, product_type, attribution_method, amount.

GET /api/v1/tenants/{tenant_name}/topic-attributions/aggregate

Multi-dimensional aggregation of topic attribution rows.

Parameter Type Default Description
group_by list[string] ["topic_name"] Columns to group by (repeatable)
time_bucket string day hour, day, week, or month
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries. Defaults to UTC.
cluster_resource_id string no Filter by cluster
topic_name string no Filter by topic
product_type string no Filter by product type

Valid group_by columns: topic_name, cluster_resource_id, env_id, product_type, product_category, attribution_method.

Response:

{
  "buckets": [
    {
      "dimensions": {"topic_name": "orders"},
      "time_bucket": "2026-01-01",
      "total_amount": "42.50",
      "row_count": 3
    }
  ],
  "total_amount": "42.50",
  "total_rows": 3
}

GET /api/v1/tenants/{tenant_name}/topic-attributions/dates

List distinct dates for which topic attribution rows exist.

Response: {"dates": ["2026-01-01", "2026-01-02", ...]}

POST /api/v1/tenants/{tenant_name}/topic-attributions/export

Stream topic attribution data as CSV. Returns text/csv with Content-Disposition: attachment; filename=topic_attributions.csv.

Parameter Type Required Description
start_date date no Filter start
end_date date no Filter end
timezone string no IANA timezone for date boundaries. Defaults to UTC.

CSV columns: ecosystem, tenant_id, timestamp, env_id, cluster_resource_id, topic_name, product_category, product_type, attribution_method, amount.