Skip to content

FOCUS cost export

GET /api/cost/export/focus returns your account’s aggregated cost history as a CSV using column names from the FOCUS specification (FinOps Open Cost and Usage Specification) — BilledCost, EffectiveCost, BillingCurrency, ServiceName, and so on — so the file drops into a BI import or a spreadsheet pivot that was already built against FOCUS column names.

This is the opposite direction from the FOCUS cost source, which imports a provider’s FOCUS export into Plutus. This page is about getting Plutus’s own aggregated data back out.

The export borrows FOCUS’s column names and semantics for the data Plutus actually holds. It is not a spec-conformant FOCUS export, and it doesn’t claim to be.

A conformant export needs columns Plutus has no data model for: ListCost and ContractedCost (rate-card views distinct from what was actually billed), ServiceCategory and ChargeCategory (FOCUS’s own taxonomy, which no sync captures at ingest). Those columns are absent from the file, not emitted full of nulls — a null-padded column looks conformant to the tool reading it and silently misleads it, which is worse than a shorter, honest column set.

Check that whatever consumes the file tolerates the missing columns before wiring it into a pipeline that expects full FOCUS conformance.

Column What it holds
ChargePeriodStart, ChargePeriodEnd One UTC day. ChargePeriodEnd is exclusive and always one day after the start.
BilledCost What the provider charged for that day.
EffectiveCost The amortized figure — see the caveat below.
BillingCurrency The currency the two cost columns are denominated in.
ServiceName The service the spend is attributed to.
ProviderName The cost source’s display name (for example, AWS), not its internal id.
PricingQuantity, PricingUnit Quantity and unit, where the source reports them.
Tags Provider tags as a JSON object. A row with no tags emits {}, not a blank cell.

Rows are ordered oldest first.

  • Only cost sources currently enabled on the account. A source you’ve removed isn’t in the file.
  • The service grain only. Plutus stores the same spend once per breakdown dimension (service, region, account, usage type), so mixing dimensions into one file would double-count every dollar. service is the one dimension every provider populates, which is what lets the file honestly claim to cover the whole account. There’s no way to request a different dimension.
  • Virtual tags are not in the export. The Tags column carries the provider’s own tags. Tag rules you defined in Plutus (see Virtual tagging & cost allocation) are applied at query time and have no representation in this file.
Parameter Required Notes
start_date yes Inclusive.
end_date yes Exclusive.
cost_source_ids no Comma-separated. Narrows the export to specific sources; defaults to all enabled sources.
currency no native (default) or base. See below.
GET /api/cost/export/focus?start_date=2026-07-01&end_date=2026-08-01

There’s no download button in the app for this yet — it’s an API endpoint. It authenticates with your normal Plutus login session rather than an MCP or usage-ingestion API key, so opening the URL in a browser tab where you’re already signed in to Plutus downloads the file.

By default each row carries the amount as the provider billed it, with BillingCurrency set to that provider’s own currency. This is deliberate: FOCUS makes BillingCurrency a per-row field precisely because a multi-provider bill is mixed-currency, and the point of a FOCUS-formatted file is usually to reconcile line items against a provider’s own invoice, which is denominated natively.

?currency=base is the opposite mode: every row is converted to the fixed USD base Plutus aggregates on, and BillingCurrency reads USD on every row. Use it when you want one column you can sum without an FX step; don’t use it when you’re reconciling against an invoice. See Multi-currency.

  • 366 days per request. A wider window is rejected with an error rather than truncated. The export is synchronous — one HTTP request, no background job to poll — so the window has to stay small enough for a single response. Export a longer history as consecutive requests.
  • Paid plans only. On Hobby, the endpoint returns a 403 pointing at the upgrade. See Plans & tiers.

EffectiveCost is the amortized figure — prepaid commitments spread across the term they cover. Amortized data only exists from the date Plutus started capturing it, and it can’t be backfilled. Rows from before that date carry billed-as-amortized (EffectiveCost equal to BilledCost), which is not a true amortized figure.

If your requested window starts before that date, the response carries an X-Focus-Export-Warning header saying so. The export still runs — the warning doesn’t block it, and it isn’t in the CSV body, so a script that only reads the body won’t see it. See Billed vs. amortized cost.