Cost Attribution
Because Stategraph holds your whole fleet's state of record, it can answer the question a per-file cost plugin cannot: who owns this spend, and how is it trending? The tenant endpoints roll up the latest snapshot of every live state and break it down by provider, type, or tag, in a single call.
GET /api/v1/tenants/{tenant_id}/costs[?tag_key=KEY] # rollup + breakdowns
GET /api/v1/tenants/{tenant_id}/costs/tag-keys # tag keys available to group by
GET /api/v1/tenants/{tenant_id}/costs/history[?from&to&group_by] # cost over time
Tenant Rollup
curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
"http://localhost:8080/api/v1/tenants/$TENANT_ID/costs"
One call returns the tenant total, coverage, a by_provider and by_type breakdown, and a per-state list:
{
"monthly_cost": "1573.964000",
"currency": "USD",
"coverage_percent": 51.3,
"by_provider": [
{ "name": "aws", "monthly_cost": "1573.964000", "hourly_cost": "2.156116", "resource_count": 221 }
],
"by_type": [
{ "name": "aws_db_instance", "monthly_cost": "1179.900000", "resource_count": 5 },
{ "name": "aws_elasticache_cluster", "monthly_cost": "360.620000", "resource_count": 2 },
{ "name": "aws_instance", "monthly_cost": "31.244000", "resource_count": 4 }
],
"states": [
{ "state_name": "acme-data-stores", "monthly_cost": "1509.640000", "coverage_percent": 50.0,
"resource_count": 24, "state_id": "5156028b-…" }
]
}
Soft-deleted states are excluded. A never-priced state appears in states[] with its identity only and no cost fields, which is different from a $0 state.
Attribution by Tag
This is the "who owns this spend" view. First discover which tag keys exist across the fleet:
curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
"http://localhost:8080/api/v1/tenants/$TENANT_ID/costs/tag-keys"
{ "tag_keys": ["Environment", "Project", "Role", "Service", "Team", "Tier"] }
Then break the rollup down by one of them with ?tag_key=:
curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
"http://localhost:8080/api/v1/tenants/$TENANT_ID/costs?tag_key=Team"
by_tag comes back with one row per value of that key:
{
"by_tag": [
{ "name": "data", "monthly_cost": "1149.020000", "resource_count": 13 },
{ "name": "engineering", "monthly_cost": "7.592000", "resource_count": 20 },
{ "name": "platform", "monthly_cost": "2.200000", "resource_count": 52 },
{ "name": "sre", "resource_count": 17 },
{ "name": "untagged", "monthly_cost": "415.152000", "resource_count": 103 }
]
}
Two things to read carefully:
untaggedrolls up every resource missing that key. A largeuntaggedfigure is usually a tagging-hygiene signal, not a real owner.- Absent money is not
$0. Thesrerow above has 17 resources but nomonthly_cost, because none of them were priced (free-to-create resources, or unsupported types). A$0value means "priced, costs nothing"; an absent field means "nothing here was priced." Do not render them the same way.
Group by Environment, Project, Service, or any other key the same way, for example ?tag_key=Environment to split production from staging.
Trends Over Time
History is derived from the append-only snapshot trail. Each state's most recent snapshot is carried forward across recompute gaps, so the series is real, not interpolated.
curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
"http://localhost:8080/api/v1/tenants/$TENANT_ID/costs/history?group_by=provider"
{
"points": [
{
"date": "2026-06-09",
"monthly_cost": "1573.964000",
"hourly_cost": "2.156116",
"groups": [
{ "name": "aws", "monthly_cost": "1573.964000", "resource_count": 221 }
]
}
]
}
There is one points[] entry per day, oldest first, each carrying the day's tenant total. Useful parameters:
| Parameter | Description |
|---|---|
group_by |
provider or type, adding a groups[] breakdown to each point |
from / to |
Window bounds, as full ISO 8601 / RFC 3339 timestamps (for example 2026-06-01T00:00:00Z), not bare dates |
A date-only value returns 400 with id INVALID_DATE_PARAM.
curl -H "Authorization: Bearer $STATEGRAPH_API_KEY" \
"http://localhost:8080/api/v1/tenants/$TENANT_ID/costs/history?from=2026-06-01T00:00:00Z&to=2026-06-09T00:00:00Z"
Next Steps
- Querying Cost Data - Go beyond the prebuilt rollups with SQL
- State & Resource Cost - Drill into a single state's per-resource breakdown