Skip to main content Skip to content

Reports & Analytics

Cost flow Sankey, anomaly detection, trends, snapshots, team and tag attribution, budgets, and unit economics.

12 min read Last updated: 

Track cloud costs, savings from automated scheduling, and monitor resource utilization across all your connected accounts.

Dashboard Summary

GET /reports/summary

Get an overall cost and savings summary for the current period.

Response
{
"data": {
"totalCostUSD": 12450.50,
"totalSavingsUSD": 3280.75,
"resourceCount": 156,
"period": "2025-01"
}
}

Cost Flow (Sankey)

A configurable Sankey view of how cost flows across providers, accounts, regions, resource types, services, purchase types, and teams. The default flow is Provider -> Account -> ResourceType -> Team and can be reshaped to any ordered sequence of dimensions; the URL is shareable so a drilldown can be sent in chat.

Supported dimensions

  • provider
  • cloud_account_id
  • region
  • resource_type
  • service_name
  • purchase_type
  • team_id
  • resource_uid (drilldown only)

Overlays

  • Savings overlay: highlights links carrying idle, orphan, or right-sizing savings opportunities surfaced by Recommendations.
  • Unattributed overlay: surfaces cost flowing to resources missing team or tag attribution. Use this to find gaps in Smart Tags coverage.
GET /reports/costs/breakdown

Group cost by an ordered list of dimensions. Powers the Sankey and can back treemaps or custom dashboards.

Query parameters:

  • dims: comma-separated dimension list, in order. Allowlisted to the dimensions above.
  • from / to. ISO 8601 date range.
  • filter[dim]=value: repeatable, scopes the breakdown.
Example
curl "https://api.zop.dev/reports/costs/breakdown?dims=provider,cloud_account_id,resource_type,team_id&from=2026-04-01&to=2026-04-27" \
-H "Authorization: Bearer <token>"
Response
{
"data": {
"nodes": [
{ "id": "aws", "dim": "provider" },
{ "id": "aws|123456789012", "dim": "cloud_account_id", "label": "Production AWS" },
{ "id": "aws|123456789012|ec2", "dim": "resource_type" },
{ "id": "aws|123456789012|ec2|team_platform", "dim": "team_id", "label": "Platform" }
],
"links": [
{ "source": "aws", "target": "aws|123456789012", "valueUSD": 4200.50 },
{ "source": "aws|123456789012", "target": "aws|123456789012|ec2", "valueUSD": 2800.00 },
{ "source": "aws|123456789012|ec2", "target": "aws|123456789012|ec2|team_platform", "valueUSD": 1900.50 }
],
"totalUSD": 4200.50
}
}

Export

The Sankey supports CSV and PNG export. CSV exports the underlying flow rows (source, target, dimension, value); PNG exports the rendered diagram with the same URL-encoded state.

Cost Anomaly Detection

ZopNight detects unusual cost spikes across five dimensions (org, cloud account, resource group, resource, team) using percentage deviation and z-score analysis, with 14-day root-cause attribution. See Cost Anomaly Detection for the full feature, including detection algorithm, notification cooldown, dedup, and the two-level drawer.

GET /reports/anomalies

List anomaly records for a window. Suppressed records map to severity info.

GET /reports/trends

Get daily cost and savings trend data for charts and dashboards.

Response
{
"data": {
"items": [
{
"date": "2025-01-15",
"costUSD": 425.30,
"savingsUSD": 112.50
},
{
"date": "2025-01-16",
"costUSD": 418.20,
"savingsUSD": 119.80
}
]
}
}
GET /reports/cost-history

Long-range cost history for charts that span multiple months. Accepts granularity (daily, weekly, monthly) and a date range.

GET /reports/metrics

Aggregate utilization metrics across the org (CPU, memory, disk) used by the dashboard hero. Backed by the discoverer's metrics enrichment.

GET /reports/resources/metrics

Per-resource utilization metrics over a window (CPU, memory, network). Used by the resource detail drawer.

GET /reports/resources/activity

Per-resource activity timeline (state transitions, scheduler events, action submissions, configuration changes).

POST /reports/export

Export a cost report summary as CSV. The export runs in the background and a download link is emailed to you.

Request
curl -X POST https://api.zop.dev/reports/export \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"from": "2026-04-01",
"to": "2026-04-30"
}'

The body accepts from and to (YYYY-MM-DD), and optionally period, sortBy and sortOrder. The request returns immediately; when the CSV is ready you receive an email with a signed download link. No download URL is returned in the response, and only CSV is produced.

Excel cost workbooks

On Reports › Summary, Export offers two reports. Standard report (CSV) is the export above. Advanced report (Excel workbook) opens the workbook page under Reports. Build the workbook sheet by sheet from the sheet templates (cost by service, account, team, region, pricing model or tag; monthly overviews; every-charge dumps by service category), and add tables to a sheet from the same templates. The page shows each sheet’s columns and checks the template as you edit; it shows no figures. Choose 1 to 24 months, then Email me the file: it builds in the background and a download link arrives by email. A deleted sheet stays in Deleted beside Customize until you undo it.

The template button beside Email me the file saves the workbook’s setup as a template under its name: it reads Save as template before the first save, Save changes after an edit and Saved once saved (Ctrl+S or Cmd+S does the same). Anyone with report access to the whole organization can open a template from the button’s menu, Open a saved template, and build the same file next month. After you email a file, the page offers to save its setup as a template too. Save as a new template in the same menu keeps a copy under a new name. If someone else saved the same template after you opened it, saving asks before replacing their version. When your organization has saved templates, Export › Advanced report first asks whether to start fresh or open one. Saving needs a role that can create policies (Admin or Editor); Viewers can open templates. Each organization can keep up to 100.

Each month is converted to your organization’s currency at that month’s month-end rate, so past months can differ slightly from the Summary tab, which uses today’s rate. Workbooks need report access to the whole organization; users with team-scoped access can still use the standard CSV.

POST /reports/workbooks/export

Build the workbook in the background and email a download link. The body is {template, from, to}, months as YYYY-MM; the response is only an acknowledgement.

Request
curl -X POST https://api.zop.dev/reports/workbooks/export \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"from": "2026-07",
"to": "2026-09",
"template": {
"name": "Monthly cost workbook",
"bucketSets": [{ "name": "Cost group", "rules": [
{ "name": "Compute", "when": [{ "column": "serviceCategory", "op": "in", "values": ["Compute"] }] },
{ "name": "Everything else", "default": true }
] }],
"sheets": [
{ "name": "Summary", "tables": [
{ "title": "Cost by month", "type": "monthly", "rows": ["bucket:Cost group"], "dailyAverage": true },
{ "title": "By service", "type": "pivot", "rows": ["provider", "service"] }
] },
{ "name": "Compute Dump", "tables": [
{ "type": "dump",
"filters": [{ "column": "serviceCategory", "op": "in", "values": ["Compute"] }],
"columns": [
{ "header": "Month", "source": "month" },
{ "header": "Resource", "source": "resource", "transform": "lastSegment" },
{ "header": "Service", "source": "service" },
{ "header": "Cost", "source": "measure:cost" }
] }
] }
]
}
}'

A template has a name and 1 to 12 sheets, each holding 1 to 4 tables written one under another. A pivot table groups by its rows and has one column per month plus a total; a monthly table has one row per month and a column per value of its one optional rows entry; a dump table lists its columns per month. A pivot or monthly table shows cost, or with "measure": "charges" the number of resource and meter pairs; totalHeader renames its total and a monthly table can add dailyAverage. A source is a billing dimension (such as provider, account, subAccountName, service, serviceCategory, resourceGroup, resourceName, providerResourceType, region), team (split by each team’s share of the resource), month, measure:cost, measure:costUSD, tag:<key>, bucket:<set> or blank. Optional fields: filters (op in or exclude, and "match": "contains" to match part of a value), bucketSets, costMeasure (effectiveCost or billedCost) and tagScope (accepted or all). A mistake in the template returns 400 naming the field; months with no charges, or a missing exchange rate, return 422. A sheet over Excel’s row limit fails while the file is built, after the request has returned.

POST /reports/workbooks/policies/validations

Check a workbook design before saving it, without saving anything. Body {spec: {template, schedule: null}}; returns {valid, errors[] {field, message}}. Save it with POST /policies (domain report, targetType organisation, the same spec) and list saved designs with GET /policies?domain=report.

Resource Costs

GET /reports/costs/resources

Get per-resource cost breakdown. Returns one row per resource-day by default; group_by=resource returns one row per resource summed over the window, and group_by=purchase_type|resource_type returns per-category spend totals. All grains are RBAC-scoped; the aggregated ones require from and to.

Example
curl "https://api.zop.dev/reports/costs/resources?group_by=resource&from=2026-08-09&to=2026-09-08&page=1&limit=20&sort_by=cost_usd&sort_order=desc" \
-H "Authorization: Bearer <token>"

Provider Summary

GET /reports/providers/summary

Get cost and resource count breakdown by cloud provider.

Response
{
"data": {
"aws": {
"count": 85,
"costUSD": 7200.00
},
"gcp": {
"count": 42,
"costUSD": 3150.50
},
"azure": {
"count": 29,
"costUSD": 2100.00
}
}
}

Resource Summary

GET /resources/summary

Get resource count hierarchy grouped by provider and cloud account.

Response
{
"data": {
"total": 156,
"providers": [
{
"name": "aws",
"count": 85,
"accounts": [
{
"cloudAccountId": "123456789012",
"count": 60,
"types": [
{ "resourceType": "ec2", "count": 25 },
{ "resourceType": "rds", "count": 8 },
{ "resourceType": "eks-cluster", "count": 3 }
]
}
],
"types": [
{ "resourceType": "ec2", "count": 25 }
]
}
]
}
}

Cost Attribution (Showback)

Slice cost by team (see Showback for how team attribution works) or by tag (cloud tags, GCP labels, Azure tags, and accepted smart tags). Both dimensions are computed from the same daily billing rollup, so team and tag totals always reconcile to the provider total.

By Team

GET /reports/teams

List cost per team for the selected period.

Response
{
"data": [
{
"teamID": "team_001",
"teamName": "Platform",
"costUSD": 4200.50,
"resourceCount": 42,
"percentOfTotal": 33.7
}
]
}
GET /reports/teams/{teamID}

Get a per-team breakdown by provider and resource type.

GET /reports/teams/{teamID}/resources

List resources attributed to a team with their individual cost.

GET /reports/teams/trends

Daily/weekly/monthly trend series for all teams.

By Tag

GET /reports/tags

List tag keys that have attributed cost (cloud tags, GCP labels, Azure tags, accepted smart tags).

Response
{
"data": [
{
"tagKey": "Environment",
"coverage": {
"tagged": 128,
"untagged": 18
},
"costUSD": 12450.50
}
]
}
GET /reports/tags/{tagKey}

List tag values for a given key and their attributed cost.

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

List resources that carry a given tag value with individual cost.

GET /reports/tags/trends

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

Monthly Snapshots

GET /reports/snapshots

Get historical monthly report snapshots.

Response
{
"data": [
{
"id": "snap_001",
"period": "2025-01",
"totalCostUSD": 12450.50,
"totalSavingsUSD": 3280.75,
"resourceCount": 156,
"createdAt": "2025-02-01T00:00:00Z"
},
{
"id": "snap_002",
"period": "2024-12",
"totalCostUSD": 13100.00,
"totalSavingsUSD": 2900.00,
"resourceCount": 148,
"createdAt": "2025-01-01T00:00:00Z"
}
]
}

Budgets

Set monthly cost budgets and track spending against them. Each budget targets exactly one of: a resource (resourceUid), a resource group (resourceGroupId), a cloud account (cloudAccountId, the provider’s account, project or subscription ID) or an AI provider (aiProviderId, the provider slug such as openai).

GET /budgets/summary

Get organization-wide budget summary.

Response
{
"data": {
"totalBudgetUsd": 25000.00,
"totalSpendUsd": 18500.00,
"totalRemainingUsd": 6500.00,
"overBudgetCount": 1,
"warningCount": 1,
"healthyCount": 3
}
}
GET /budgets

List all budgets.

POST /budgets

Create a budget for one resource, resource group, cloud account or AI provider.

Request
curl -X POST https://api.zop.dev/budgets \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"resourceGroupId": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"monthlyBudgetUsd": 5000.00,
"alertThresholdPercent": 80
}'
Response
{
"data": {
"id": "2b4d6f8a-0c1e-4a3b-9d5f-7e8a9b0c1d2e",
"orgId": "3f6c2a9e-8b1d-4c7e-9f2a-1d5e6b7c8a90",
"resourceGroupId": "9c8b7a6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"monthlyBudgetUsd": 5000.00,
"alertThresholdPercent": 80,
"currentSpendUsd": 3200.00,
"remainingUsd": 1800.00,
"percentUsed": 64.0,
"status": "green",
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-20T08:00:00Z"
}
}
PUT /budgets/{budgetID}

Update a budget's monthlyBudgetUsd and alertThresholdPercent.

DELETE /budgets/{budgetID}

Delete a budget.

Budget Status Indicators

StatusConditionDescription
greenSpend < alert thresholdSpending is within normal range
yellowSpend >= alert thresholdSpending has crossed the configured alert threshold
redSpend >= 100% of budgetBudget has been exceeded

Scheduler Events

View a log of scheduler-triggered events showing which schedules fired and what actions were taken.

GET /events

List scheduler events.

Response
{
"data": [
{
"id": "evt_001",
"scheduleID": "sch_abc123",
"action": "stop",
"triggeredAt": "2025-01-20T18:00:00Z",
"resources": ["i-0abc123def456", "i-0def789abc012"],
"status": "completed"
}
]
}
POST /events

Record a scheduler event (primarily used internally by the scheduler service).

Unit Economics

Unit economics correlate spend with business KPIs, cost per order, cost per active user, cost per build minute, so teams can compare cost movement against demand rather than treating spend as a raw line item. Define a metric in /unit-metrics (push, pull, or CSV ingestion), then send values for it and read the resulting series back through Reports.

POST /unit-metric-values/{id}

Push a batch of values for a unit metric. Returns the number of rows ingested. Use for low-volume push integrations and webhooks.

POST /unit-metric-values/{id}/csv

Upload a CSV of historical values. Accepts a single CSV file per request; rows are upserted by timestamp.

POST /unit-metric-values/{id}/test-pull

Run the configured pull integration once and return the rows it produced, without persisting anything. Used by the metric editor's 'Test connection' button.

DELETE /unit-metric-values/{id}

Drop every stored value for a metric. Useful when reseeding from a corrected source.

GET /reports/unit-economics

Time-series of cost-per-unit for a chosen metric, with optional filters (provider, team, tag). Used by the Unit Economics chart on the cost dashboard.

Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·