Page 4 of 7 · Worked example · both servers
Showback Reporting
A showback report tells each team what its technology use cost — without moving money. This page walks the chain an agent walks to build one: the official FinOps Framework guidance that defines the work, the maturity bar it has to clear, the FOCUS™ columns your billing export must carry, and finally a real showback table computed from the bundled official FOCUS 1.0 sample.
Locate the work in the framework official
Showback lives in the Understand Usage & Cost domain. The framework server returns the domain definition verbatim:
That single sentence names both halves of a showback: the metadata that says who owns what (Allocation) and the reporting process that puts the number in front of them (Reporting & Analytics). The domain carries four capabilities:
| Capability | Slug | Official summary |
|---|---|---|
| Allocation | allocation | Define strategies to assign and share cost and usage using accounts, tags, labels, and other metadata, creating accountability among teams and projects within an organization. |
| Reporting & Analytics | reporting-analytics | Analyze data and create reporting to gain insights into usage patterns and spend patterns, identify opportunities for improvement, and support informed decision-making about technology resources. |
| Data Ingestion | data-ingestion | Collect, transfer, store, and normalize data from various sources, with a goal of creating a complete, contextual dataset of usage and cost data available for analysis. |
| Anomaly Management | anomaly-management | Detect, identify, alert and manage unexpected or unforecasted technology cost and usage irregularities in a timely manner to lower risk and ensure cost-effective operations. |
The two bolded capabilities carry this example; the other two are the pipeline underneath it and the alarm bell on top of it.
framework · get_entity {"entity_type": "domains"} · list_capabilities {"domain": "understand-usage-and-cost"}
Read the two capabilities official
Allocation is explicit that showback is one of its three destinations, and it names the three strategies you have to write down:
- Allocation strategy — “defining how costs should be mapped to the organization.”
- Tagging / metadata strategy — “defining how usage and resources will be mapped to the defined parts of the organization.”
- Shared cost strategy — “which defines how each set of shared resources will be allocated to budgets.”
The capability also grants permission to not solve everything at once: many early practices adopt an “informed ignore” approach, explicitly deciding to budget shared items centrally rather than allocating them out. And it closes on the standard to aim at — “the level of allocation that provides the organization with the level of information to make good decisions at its chosen level of maturity.”
Reporting & Analytics supplies the delivery half, and names showback as one of its use cases:
Note the dependency direction the official text states: “Much of the strategy for these metadata will be defined in the Allocation capability.” Allocation decides the grouping; Reporting & Analytics renders it. Build them in that order.
framework · get_capability {"capability": "allocation", "include": ["summary","definition"]} · get_capability {"capability": "reporting-analytics", "include": ["summary","definition"]}
Set the maturity bar official
The framework's own maturity model publishes sample goals per level — and the first one at every level is an allocation-coverage number. This is the target your showback is graded against:
The capability-level assessments tell you what that looks like operationally. Selected characteristics, verbatim:
| Capability | Crawl | Walk |
|---|---|---|
| Allocation | “Simple Allocation strategy where costs of accounts, projects or subscriptions are allocated to the business units, portfolios or cost centers using a list of accounts known to belong to specific cost centers or business units”; “Tagging strategy compliance is inconsistent”; “Shared costs are allocated to central budgets or platform teams directly and not charged back”. | “Cost allocation can be done to an application or service level”; “Tagging compliance is consistent in key areas or applications but not universal”; “Shared platform owners are able to showback costs generated by internal customers”. |
| Reporting & Analytics | “Use of canned reports with only basic ability to filter and alter result view”; “Reporting centered on high level cost and usage groupings with limited granularity”; “Analytic results are being manually communicated to teams”. | “Granular reporting enabling KPI tracking and showback reporting”; “Reporting tools enable custom views and aggregations”; “Dashboard reporting is provided centrally to teams”. |
Read across: showback appears explicitly at Walk in both capabilities. At Crawl you are grouping by account and mailing a spreadsheet; at Walk the platform owner can hand each internal customer its own number.
framework · get_maturity_model {} · get_maturity_assessment {"capability": "allocation"} · get_maturity_assessment {"capability": "reporting-analytics", "level": "crawl" | "walk"}
Pick the KPIs official
Three KPIs are featured on Allocation's own page. Expand for the official formula:
Allocation Accuracy Index (AAI) featured
Official data sources: On-Premises Cost Data · Resource Metadata · ERP / Accounting Systems · Audit logs. Officially related capabilities: allocation, reporting-analytics, usage-optimization.
Percentage of Costs Associated with Unallocated CSP Cloud Resources featured
Usage or Spend Apportionment Validation featured
Official data sources: CSP Billing Data · Internal Finance Metrics.
Reporting & Analytics features no KPIs of its own — get_kpis {"capability": "reporting-analytics", "featured_only": true} returns total: 0. Dropping featured_only returns 14 KPIs officially related to the capability, but every one of them is featured on some other capability's page (AAI on Allocation, Cost per API Call on Unit Economics, and so on). That is the framework being consistent with its own text: Reporting & Analytics is the surface that renders other capabilities' metrics.
framework · get_kpis {"capability": "allocation", "featured_only": true} · get_kpis {"capability": "reporting-analytics", "featured_only": true} · get_kpis {"capability": "reporting-analytics"}
The FOCUS columns a showback needs official
Now switch servers. A showback report is five questions — whose is it, what was it, when was it, what did it cost, in what currency — and FOCUS answers each with named columns. Flip the spec version to see what your export must carry:
| Column | Role in the showback | Type | Feature level | Normative reqs |
|---|
“Normative reqs” is the count of MUST/SHOULD/MAY bullets the server parses out of that column's spec page at that version — a rough proxy for how much the spec tightened. SubAccountName at 1.2 is the honest outlier: get_requirements replies “No normative requirements bullets parsed for SubAccountName.”
Two requirements are worth internalising before you group by anything. On the owner axis, at FOCUS 1.2:
So SubAccountId is Conditional, and null is a legitimate value, not a data-quality bug — those nulls are exactly the unallocated slice your AAI is measuring. On the service axis, at FOCUS 1.0:
ServiceCategory is a closed vocabulary of 19 values — identical in 1.0 and 1.2 (AI and Machine Learning, Analytics, Business Applications, Compute, Databases, Developer Tools, Multicloud, Identity, Integration, Internet of Things, Management and Governance, Media, Migration, Mobile, Networking, Security, Storage, Web, Other). That is what makes it the safe grouping key for a multi-provider showback: it is mandatory, non-null, and enumerated, so an AWS row and an Oracle row land in the same bucket without a mapping table of your own.
focus · list_versions {} · list_columns {"version": "1.0" | "1.2", "limit": 100} · get_column {"column": …, "version": "1.0" | "1.2"} × 13 columns per version, plus ServiceSubcategory / SubAccountType / BillingAccountType at 1.2 · get_requirements {"column": "SubAccountId", "version": "1.2"} · get_requirements {"column": "ServiceCategory", "version": "1.0"} · search_focus {"query": "sub account grouping", "version": "1.2"}
Score the allocation KPIs UNOFFICIAL
No official mapping from framework KPIs to FOCUS columns exists. The FOCUS server derives one and flags it on every response. Of Allocation's three featured KPIs, two are mapped and one is not:
| Featured KPI | Derived FOCUS formula |
|---|---|
| Allocation Accuracy Index (AAI) | AAI % = (SUM(BilledCost) WHERE SubAccountId IS NOT NULL AND Tags IS NOT NULL) / SUM(BilledCost) × 100. |
| Percentage of Costs Associated with Unallocated CSP Cloud Resources | % Unallocated = (SUM(BilledCost) WHERE SubAccountId IS NULL) / SUM(BilledCost) × 100. |
| Usage or Spend Apportionment Validation | Not in the mapping. calculate_kpi returns an error: “Unknown KPI "usage-or-spend-apportionment-validation" in the mapping.” Its inputs — which costs your organisation has declared shared, and the apportionment basis — are policy, not billing data. FOCUS cannot supply them, so the server declines rather than inventing a denominator. |
Running the two mapped ones over the bundled official FOCUS 1.0 sample:
108.30%
An allocation-accuracy score above 100% is not a rounding artifact — it is a finding. The 289 untagged rows in this sample sum to −$1.70234969920 of BilledCost, because one of them is a ChargeCategory = "Credit" row worth −$2.61370000000 (“AWS Open Source Promotional Credits”). Credits and adjustments usually arrive without tags, so they shrink the denominator while contributing nothing to the numerator. The lesson for a production showback: decide up front how credits and adjustments are allocated, or your coverage ratio will drift above 100% and stop meaning anything.
Both values above are UNOFFICIAL: derived formula, derived computation, bundled sample data only — official: false on every response. They are not FinOps Foundation or FOCUS project outputs.
focus · get_kpi_mapping {"capability": "allocation", "version": "1.2"} · calculate_kpi {"kpi": "allocation-accuracy-index-aai", "version": "1.0", "sample": "official"} · calculate_kpi {"kpi": "percentage-of-costs-associated-with-unallocated-csp-cloud-resources", "version": "1.0", "sample": "official"} · calculate_kpi {"kpi": "usage-or-spend-apportionment-validation", …} → error
Build the report computed from bundled sample
Everything below is computed from the bundled official sample for illustration — data/focus/samples/1.0/official/focus_sample.csv, 1,000 rows of real, anonymized multi-provider billing data published by the FOCUS project under CC BY 4.0 (AWS 942 · Microsoft 51 · Oracle 7 rows; all BillingCurrency = USD; 999 rows in billing period 2024-09-01 → 2024-10-01). It is a sample: the totals are cents, not a real organisation's bill. The shape of the exercise is what transfers.
Showback by service — SUM(EffectiveCost) GROUP BY ServiceCategory
| ServiceCategory | Rows | EffectiveCost (USD) | Share |
|---|---|---|---|
| Compute | 443 | 14.75656109 | 98.531% |
| Databases | 21 | 0.37096774 | 2.477% |
| Storage | 209 | 0.00088292 | 0.006% |
| Networking | 168 | 0.00000000 | 0.000% |
| Management and Governance | 79 | 0.00000000 | 0.000% |
| Other | 47 | 0.00000000 | 0.000% |
| Integration | 18 | 0.00000000 | 0.000% |
| Identity | 4 | 0.00000000 | 0.000% |
| Security | 2 | 0.00000000 | 0.000% |
| AI and Machine Learning | 9 | −0.15189756 | −1.014% |
| Total | 1,000 | 14.97651419 | 100.000% |
Nine of the 19 allowed ServiceCategory values never appear in this sample; they are omitted rather than shown as empty rows. The AI and Machine Learning line is negative: five of its nine rows carry a negative EffectiveCost, so the category nets out as a credit against the bill.
Showback by owner — SUM(EffectiveCost) GROUP BY SubAccountName
The sample's owner axis is emphatically non-degenerate: 73 distinct SubAccountId values resolving to 68 distinct SubAccountName values. It is also brutally concentrated — 939 of the 1,000 rows have an EffectiveCost of exactly zero, and 64 of the 68 names total exactly $0.00.
| SubAccountName | Rows | EffectiveCost (USD) | Share |
|---|---|---|---|
| Atlas Orion | 230 | 14.58088000 | 97.358% |
| Orion Pioneer | 63 | 0.21995208 | 1.469% |
| Apollo Eclipse | 4 | 0.17568152 | 1.173% |
| Pioneer Zenith | 16 | 0.00000059 | 0.000% |
| 64 other sub-account names | 687 | 0.00000000 | 0.000% |
| Total | 1,000 | 14.97651419 | 100.000% |
Why you group by ID, not by name. “Atlas Orion” is a single line above, but it is three sub-accounts across three providers: AWS 11353890204 ($13.00000000, 225 rows), Microsoft /subscriptions/ed570627-… ($1.58088000, 2 rows), and Oracle ocid6.tenancy.oc6..aaaa… ($0.00000000, 3 rows). Names are for humans; SubAccountId is the join key.
The report itself — owner × service, non-zero cells only
| SubAccountName | ServiceCategory | Rows | EffectiveCost (USD) |
|---|---|---|---|
| Atlas Orion | Compute | 188 | 14.58088000 |
| Orion Pioneer | Databases | 1 | 0.37096774 |
| Apollo Eclipse | Compute | 2 | 0.17568072 |
| Orion Pioneer | AI and Machine Learning | 9 | −0.15189756 |
| Orion Pioneer | Storage | 35 | 0.00088190 |
| Apollo Eclipse | Storage | 1 | 0.00000080 |
| Pioneer Zenith | Compute | 9 | 0.00000037 |
| Pioneer Zenith | Storage | 1 | 0.00000022 |
| 8 non-zero cells of 191 populated pairs | 246 | 14.97651419 | |
Computed offline from the committed CSV with a small Python aggregation (exact decimal arithmetic, no floating point), not by an MCP tool — calculate_kpi computes mapped KPIs, not arbitrary group-bys. Figures are shown at 8 decimal places because at this sample's scale rounding to cents would erase four of the eight rows.
offline · python3 csv.DictReader over data/focus/samples/1.0/official/focus_sample.csv · Decimal sums grouped by ServiceCategory, SubAccountName, and the pair
Takeaways
What a practitioner walks away with
- Thirteen FOCUS 1.0 columns carry a complete showback — BillingAccountId/Name, SubAccountId/Name, Tags, ServiceCategory, ServiceName, ChargePeriodStart/End, ChargeCategory, EffectiveCost, BilledCost, BillingCurrency. All thirteen survive unchanged into 1.2, so a 1.0 pipeline keeps running.
- Group by ServiceCategory, not ServiceName. ServiceCategory is Mandatory, non-null, and a closed 19-value vocabulary identical across 1.0 and 1.2 — the one axis that is comparable across providers without a mapping table you maintain.
- Use EffectiveCost for showback, not BilledCost. EffectiveCost is the amortized cost after discounts and the applicable portion of prepaid purchases — it is what the team actually consumed. Across this sample the two totals differ by $5.54371254, or 27.02% of BilledCost ($14.97651419 effective vs $20.52022673 billed), so the choice changes every line of the report.
- Nulls in SubAccountId are spec-legal. The column is Conditional and MUST be null when the charge is not related to a sub account. Those rows are your unallocated slice — measure them, do not "fix" them.
- Decide the credit/adjustment policy before you publish. The untagged rows in this sample net to −$1.70 of BilledCost, which is why the derived AAI reads 108.30%. A coverage ratio that can exceed 100% is a ratio nobody trusts.
- Aim at the published bar. Crawl is ≥70% of cost allocated to a known owner, Walk ≥85%, Run >90% — official sample goals, not a vendor's. Showback itself is a Walk-level behaviour in both Allocation and Reporting & Analytics.
- Some KPIs are honestly out of reach. Usage or Spend Apportionment Validation has no FOCUS mapping because its inputs are your shared-cost policy, not your billing export. A tool that refuses is more useful than one that guesses.
Next: the same two servers applied to rate optimization, where the chain ends in a single computed Effective Savings Rate — the forecasting maturity journey, which starts from the Crawl→Walk gap instead of from a report — or Quick Q&A, four unscripted live prompts with no pre-planned chain at all.