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_corsandapi.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.
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.
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: List of {tracking_date, billing_gathered, resources_gathered, chargeback_calculated} per date.
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 |
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 |
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 |
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.
GET /api/v1/tenants/{tenant_name}/chargebacks/{dimension_id}¶
Get a single chargeback dimension with its tags.
Response: Dimension fields + tags array (each with tag_id, tag_key, tag_value, display_name, created_by, created_at).
PATCH /api/v1/tenants/{tenant_name}/chargebacks/{dimension_id}¶
Update tags on a chargeback dimension. Three operations available (can combine):
| Body field | Type | Effect |
|---|---|---|
tags |
list | Replace all existing tags with these |
add_tags |
list | Add these tags (keeps existing) |
remove_tag_ids |
list[int] | Remove specific tags by ID |
Each tag in tags / add_tags requires: tag_key, display_name, created_by.
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 |
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 | Description |
|---|---|---|
resource_type |
string | Filter by type |
status |
string | Filter by status |
active_at |
datetime | Resources active at this point in time |
period_start + period_end |
datetime | Resources active during this period |
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 | Description |
|---|---|---|
identity_type |
string | Filter by type |
active_at |
datetime | Identities active at this point |
period_start + period_end |
datetime | Identities active during period |
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": 3, "topic": 42}, "identity_counts": {"service_account": 12, "user": 5}}
Tags¶
GET /api/v1/tenants/{tenant_name}/chargebacks/{dimension_id}/tags¶
List tags for a specific chargeback dimension.
POST /api/v1/tenants/{tenant_name}/chargebacks/{dimension_id}/tags¶
Create a tag on a dimension. Returns 201.
Body: {"tag_key": "team", "display_name": "Platform Team", "created_by": "admin"}
tag_value is auto-generated as a UUID by the backend.
GET /api/v1/tenants/{tenant_name}/tags¶
List all tags for a tenant with denormalized dimension context. Paginated.
| Parameter | Type | Description |
|---|---|---|
search |
string | Filter tags by key or display name |
Response fields per item: Tag fields + identity_id, product_type, resource_id from the parent dimension.
PATCH /api/v1/tenants/{tenant_name}/tags/{tag_id}¶
Update a tag's display name.
Body: {"display_name": "New Name"}
DELETE /api/v1/tenants/{tenant_name}/tags/{tag_id}¶
Delete a tag. Returns 204.
POST /api/v1/tenants/{tenant_name}/tags/bulk¶
Bulk tag by explicit dimension IDs.
Body:
{
"dimension_ids": [1, 2, 3],
"tag_key": "team",
"display_name": "Platform",
"created_by": "admin",
"override_existing": false
}
Response: {"created_count": 2, "updated_count": 0, "skipped_count": 1, "errors": []}
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 by chargeback filters (resolves matching dimension IDs server-side).
Body: Same as bulk + filter fields: start_date, end_date, identity_id, product_type, resource_id, cost_type.
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",
"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 |
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.
Default columns: timestamp, resource_id, product_category, product_type, identity_id, cost_type, amount, allocation_method, tags.