# Showback (Cost Attribution)

> Slice your total cloud bill by team, tag, or both. ZopNight reconciles team and tag totals to the org-wide total from the same daily billing rollup.

Source: https://zop.dev/developer-docs/operations/showback

---

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 computes showback from the same daily billing rollup that powers [Reports](https://zop.dev/docs/operations/reports), so team and tag totals always reconcile to the org-wide total.

**Info**

Showback is not a separate aggregation. It's the same daily cost records sliced by different dimensions, with accepted smart tags layered in for resources whose owners haven't tagged them yet.

## By Team

Team attribution is derived from [resource-team assignments](https://zop.dev/docs/administration/users-teams). A resource that's not assigned to any team rolls up under `Unassigned` in the team report.

### GET /reports/teams

List cost per team for the selected period.

```json title="Response"
{
  "data": [
    {
      "teamID": "team_001",
      "teamName": "Platform",
      "costUSD": 4200.50,
      "resourceCount": 42,
      "percentOfTotal": 33.7
    },
    {
      "teamID": null,
      "teamName": "Unassigned",
      "costUSD": 312.00,
      "resourceCount": 14,
      "percentOfTotal": 2.5
    }
  ]
}
```

### GET /reports/teams/{teamID}

Per-team breakdown by provider and resource type.

### GET /reports/teams/{teamID}/resources

Per-resource cost for a team — used for the drilldown table.

### GET /reports/teams/trends

Daily / weekly / monthly trend series for all teams.

**Info**

When [cost anomaly detection](https://zop.dev/docs/operations/anomaly-detection) finds a spike attributed to a specific team, the showback trend chart displays a pulsing severity-coloured dot on the affected day. Clicking the dot opens the anomaly detail panel with root cause analysis and affected resources. The team detector filters out cross-team redistribution (resource retagging) so only genuine cost growth triggers anomalies.

## By Tag

Tag attribution covers cloud-native tags (AWS tags, GCP labels, Azure tags) plus accepted [smart tags](https://zop.dev/docs/operations/smart-tags). Each report endpoint returns tag coverage so you know how much of the total is fully attributed vs. attributed to `Unknown`.

### GET /reports/tags

List tag keys with attributed cost. Used to build the tag-key picker.

```json title="Response"
{
  "data": [
    {
      "tagKey": "Environment",
      "coverage": { "tagged": 128, "untagged": 18 },
      "costUSD": 12450.50
    },
    {
      "tagKey": "Team",
      "coverage": { "tagged": 110, "untagged": 36 },
      "costUSD": 12450.50
    }
  ]
}
```

### GET /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.

```json title="Response"
{
  "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": "billing"
  }
}
```

**Info**

`page` AND `limit` are required when `unit=pairs` — the handler returns `400 missing param` on either absent (payload-bomb prevention). `size` is accepted as a legacy alias for `limit`. `limit` is server-clamped to 100. Sort allowlist: `cost` (default) / `savings` / `resourceCount` / `name`; `(tagKey ASC, tagValue ASC)` is the deterministic tiebreak. Filter axes — `tagKey`, `tagValue`, `provider`, `resourceType` — accept CSV values and intersect AND-wise. Chart-chip exact-tuple filters use repeated `pairKey` / `pairValue` query params (positional, equal counts; key-without-value chips are rejected with `400 invalid param` in pairs mode). `prevCostUSD` is omitted when the prev-period lookup failed or the pair didn't exist last period. Keys-mode, pairs-mode, AND values-mode (`GET /reports/tags/{tagKey}` including its per-row byProvider/byResourceType breakdowns) all read the same `cost_allocation_daily` snapshot and apply the same RBAC scoping, so totals reconcile across the chart, table, and the row-expand detail on a single screen.

### GET /reports/tags/{tagKey}

List tag values for a key with their attributed cost.

### GET /reports/tags/{tagKey}/values/{tagValue}/resources

List resources carrying a given tag value with their per-resource cost.

### GET /reports/tags/trends

Daily / weekly / monthly trend series filtered by tag key, value, provider, or type.

## Coverage & Reconciliation

- **Tagged vs. untagged.** The `coverage` field on tag responses surfaces how many of the period's resources carry the key. Low coverage usually means the tag is inconsistent across accounts — [Smart Tags](https://zop.dev/docs/operations/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 as `untaggedCostUsd` — 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.** Sum across all teams (or across all values for a given tag key) always equals the org's total cost for the period. If they don't, that's a bug — file it.
- **Time alignment.** Showback uses the same calendar month boundaries as billing exports — not deploy-day or your fiscal calendar. For fiscal-month views, export and re-aggregate downstream.

For exports of these reports as CSV/JSON, use the `POST /reports/export` endpoint documented in [Reports & Analytics](https://zop.dev/docs/operations/reports).
