Showback (Cost Attribution)
Slice your total cloud bill by team, tag, or both. Endpoints for team and tag cost reports, how shared resources split, and how totals reconcile.
Showback is the practice of slicing your total cloud bill by the organizational unit that incurred it — by team, by tag, or by both. ZopNight builds showback from the same daily cost records that power Reports.
By Team
Team attribution is derived from resource-team assignments, including resources a team owns through a resource group. Cost that belongs to no team is not a row in items. It is reported in unattributedCostUsd and unattributedCount.
/reports/teams List cost per team for the selected period.
{ "data": { "items": [ { "teamId": "team_001", "teamName": "Platform", "allocatedCostUsd": 4200.5, "allocatedSavingsUsd": 310.25, "resourceCount": 42, "percentOfTotal": 33.7 } ], "totalOrgCostUsd": 12450.5, "totalOrgSavingsUsd": 480.0, "unattributedCostUsd": 312.0, "unattributedCount": 14, "byProvider": { "aws": 9800.5, "gcp": 2650.0 }, "byResourceType": { "vm": 6100.0, "rds": 2200.0 }, "period": "2026-09", "hasBilling": true, "costSourceLabel": "Unblended Cost" }}Query params: period (YYYY-MM, defaults to the current month), or from and to (YYYY-MM-DD, at most 366 days apart). Sort with sortBy (cost, savings, resourceCount, name) and sortOrder (asc or desc, default desc). The response may also carry a costDataMeta block that says how fresh the data is. costSourceLabel is explained on Billing.
/reports/teams/{teamID} Per-team breakdown by provider and resource type.
/reports/teams/{teamID}/resources Per-resource cost for a team — used for the drilldown table.
/reports/teams/trends Daily / weekly / monthly trend series for all teams.
By Tag
Tag attribution covers cloud-native tags (AWS tags, GCP labels, Azure tags) plus accepted smart tags. Each row’s tagSource says where the tag came from: cloud, auto, inherited, derived, or mixed. Untagged cost is reported separately in untaggedCostUsd and untaggedCount.
Every tag endpoint below takes an optional tagScope:
accepted(default): cloud tags, tags inherited from a parent resource, and accepted smart tags.all: also tags your tagging policies derive that nobody has accepted yet. They show astagSource: "derived". A real cloud tag always wins over a derived value, and a resource covered only by a derived value is no longer counted as untagged.
Any other value returns 400. In the app, ticking Policy (not accepted) in the Tags tab’s Source filter sets tagScope=all for the chart and table, and the Coverage card then shows policy tags as their own band.
/reports/tags List tag keys with attributed cost. Used to build the tag-key picker.
{ "data": { "items": [ { "tagKey": "Environment", "tagSource": "cloud", "costUsd": 9800.5, "savingsUsd": 360.0, "resourceCount": 128, "valueCount": 4 } ], "totalCostUsd": 12450.5, "totalSavingsUsd": 480.0, "taggedCostUsd": 12138.5, "untaggedCostUsd": 312.0, "untaggedCount": 14, "period": "2026-09", "hasBilling": true, "costSourceLabel": "Unblended Cost" }}Keys-mode takes the same period, from, to, sortBy and sortOrder params as the team list. Without page and limit it returns every key. With them it returns one page plus total, page and limit. Add includeValues=true to inline each key’s values, byProvider and byResourceType for that page, so you don’t need one GET /reports/tags/{tagKey} call per key.
/reports/tags?unit=pairs&page={n}&limit={n} Server-paginated list of (tagKey, tagValue) pairs. Powers the Tag Cost Attribution table without the prior 100-key client-side cap.
{ "data": { "items": [ { "tagKey": "Environment", "tagValue": "prod", "tagSource": "cloud", "costUsd": 4200.50, "savingsUsd": 120.00, "resourceCount": 32, "prevCostUsd": 3950.00 } ], "total": 248, "page": 1, "limit": 50, "totalCostUsd": 12450.50, "totalSavingsUsd": 480.00, "untaggedCostUsd": 312.00, "untaggedCount": 14, "period": "2026-06", "hasBilling": true, "costSourceLabel": "Unblended Cost" }}| Query param | Values |
|---|---|
sortBy | cost (default), savings, resourceCount, name |
tagKey, tagValue, provider, resourceType | Comma-separated; all filters must match |
pairKey + pairValue | Repeat in matching pairs to filter on exact key/value tuples |
source | cloud, auto, inherited, mixed, derived (comma-separated); derived needs tagScope=all, otherwise 400 |
search | Substring of key:value, up to 256 characters |
/reports/tags/{tagKey} List tag values for a key with their attributed cost.
/reports/tags/{tagKey}/values/{tagValue}/resources List resources carrying a given tag value with their per-resource cost.
/reports/tags/trends Daily / weekly / monthly trend series filtered by tag key, value, provider, or type.
Coverage & Reconciliation
- Tagged vs. untagged.
untaggedCostUsdanduntaggedCountshow how much cost carries no tag. Low coverage usually means tags are inconsistent across accounts — Smart Tags can close the gap. - Tag Coverage bar. The keys-mode response embeds
taggedCostUsd— the per-resource-deduplicated tagged total, read from the same snapshot asuntaggedCostUsd— so the Tag Coverage bar is computed within one data universe and reads exactly 0% when nothing is tagged. The field is omitted unless both totals queries (tagged and untagged) succeed — presenting one beside a zeroed other would render a false 0% or 100%; the UI then falls back to deriving coverage from the teams org total, which can drift by up to one snapshot cycle. - Reconcile to org total. In the team list, the sum of every team’s
allocatedCostUsdplusunattributedCostUsdequalstotalOrgCostUsd. The teams alone match it only when nothing is unattributed.percentOfTotalis measured againsttotalOrgCostUsd, so team percentages leave out the unattributed share. - Billed spend with no resource. With billing connected, charges that match no discovered resource
(tax, support, data transfer, undiscovered services) can’t be assigned to a team. They land in
unattributedCostUsd. See Billing. - Teams vs. tags. The team list reads cost records live. Tag reports read the daily snapshot. The two totals can differ until the snapshot catches up.
- Days not built yet. If some days in the window haven’t been broken down by tag or team yet, tag
endpoints and the team resources and trends endpoints return
409. They fill in automatically overnight. - Time alignment.
period=YYYY-MMuses calendar month boundaries — not deploy-day or your fiscal calendar. For fiscal-month views, passfromandto, or export and re-aggregate downstream.
For exports of these reports as CSV/JSON, use the POST /reports/export endpoint documented in Reports & Analytics.