Billing Integration
ZopNight replaces rack-rate cost estimates with billed cost from your cloud provider. Endpoints for sync status, per-account verification, raw line items, and the FOCUS 1.4 dataset.
ZopNight replaces its rack-rate cost estimates with the billed cost from each connected cloud account. It syncs billing data nightly. The endpoints on this page let you check sync state, verify one account, and read the raw billing data.
Cost Source
You choose where cost comes from under Settings → Preferences → Cost source. Each cloud account can override it under Settings → Cloud Accounts.
| Option | What you get |
|---|---|
| Estimates only | Rack-rate cost from public list prices. No billing access needed and no charges. |
| Your billing export | Billed cost from the Azure cost export and the GCP BigQuery billing export. No per-request charge. AWS accounts stay on estimates. |
| Export + billing API | Also reads AWS cost from AWS Cost Explorer. AWS bills each request ($0.01) to your own AWS account, so you must type CONFIRM to pick it. |
What each provider’s billed figure means:
- AWS: unblended cost.
- Azure: amortized cost. Reservation fees are spread across their term.
- GCP: net of credits. Committed-use discounts, sustained-use discounts, promotions and free tier are netted off the list charge. Nothing is spread across a term.
Report responses carry a costSourceLabel that names this basis:
Unblended Cost, Amortized Cost, Net of Credits, Mixed (by provider)
when providers differ, or Rack Rate when no billed rows exist for the window.
Org-Wide Sync Status
/billing/sync-status Returns the billing sync state of every cloud account in the org.
{ "data": { "accounts": [ { "id": "7f3c…", "orgId": "org_123", "cloudAccountId": "b1d2…", "provider": "aws", "lastSyncAt": "2026-09-29 19:40:12", "lastSuccessAt": "2026-09-29 19:40:12", "syncState": "success", "hasResourceLevel": true, "backfillComplete": true, "backfillFailedAttempts": 0, "billingCurrency": "USD", "invoiceTotalUsd": 12450.5, "invoiceTotalMonth": "2026-08", "effectiveFeed": "ce_api", "effectiveReason": "ce_api (paid CE request)", "effectiveSince": "2026-09-01 19:40:12", "createdAt": "2026-06-02T10:15:00Z", "updatedAt": "2026-09-29T19:40:12Z" } ] }}| Field | Description |
|---|---|
cloudAccountId, provider | The account the row describes |
lastSyncAt | When the last sync ran |
lastSuccessAt | When the last successful sync finished |
lastError | The last failure reason, if any |
syncState | Current state. The values are listed below |
effectiveFeed, effectiveReason, effectiveSince | Which billing feed the last capture used, why, and since when |
billingCurrency, invoiceTotalUsd, invoiceTotalMonth | The account’s billing currency and its last invoice total |
hasResourceLevel | Whether the billing data includes per-resource costs |
backfillCursor, backfillComplete, backfillFailedAttempts | Progress of the historical backfill |
syncState is one of:
| Value | Meaning |
|---|---|
pending | No sync has run yet. |
syncing | A sync or verification is in progress. |
success | The last sync worked. |
failed | The last sync failed. See lastError. |
no_permission | The credentials lack billing read access. |
skipped | Not attempted, because the cost source setting says not to. |
unavailable | ZopNight can’t reach this account’s billing with the credential it holds. |
effectiveFeed is the billing feed the last capture used: cur2 (AWS
CUR 2.0 export), ce_api (AWS Cost Explorer), azure_dcr (Azure cost
export), gcp_bq (GCP BigQuery export), or none. Fields with no value
yet are omitted.
Verifying a Cloud Account
/billing/verify Check that one cloud account's billing access works. Needs org-wide access.
{ "cloudAccountId": "b1d2…", "provider": "aws"}{ "data": { "id": "", "orgId": "org_123", "cloudAccountId": "b1d2…", "provider": "aws", "syncState": "syncing", "hasResourceLevel": false, "backfillComplete": false, "backfillFailedAttempts": 0, "createdAt": "0001-01-01T00:00:00Z", "updatedAt": "0001-01-01T00:00:00Z" }}Verification runs per cloud account. Both body fields are required.
provider is one of aws, azure, gcp or snowflake.
The call returns at once with syncState: "syncing". The check runs in
the background and reads about one recent day of billing data. Poll
GET /billing/sync-status until that account shows success,
no_permission or failed.
- 403: only users with org-wide access can verify.
- 404: the cloud account isn’t in this org.
- 429: the account was synced in the last 60 seconds, or too many verifications are running.
If the account is already syncing, the call returns its current status and starts nothing new.
Historical Backfill
After an account connects, a nightly job walks billing history backwards in 7-day chunks. It reaches back up to:
| Provider | History |
|---|---|
| AWS | 365 days |
| GCP | 365 days |
| Azure | 90 days |
| Others | 30 days |
backfillComplete turns true in the sync-status response once the
walk is done.
Unattributed Spend
Some billed charges match no discovered resource. Examples are tax,
support, data transfer and services ZopNight doesn’t discover. ZopNight
keeps these charges so totals match your invoice. It groups them by
service and reports them as unattributedCostUsd on
GET /reports/summary and on the team report. See
Showback.
Raw Line Items
/billing/line-items Query raw billed line items. Group, filter and sum any dimension. Needs org-wide access.
Required: from and to (YYYY-MM-DD, inclusive).
Optional:
groupBy, up to 8 dimensions, comma-separated. For exampleservice,region.groupByTag: group by one tag key.groupByCostCategorydoes the same for a cost category.measures, which sums to return. For examplebilledCost,effectiveCost,listCost,usageAmount,rowCount.- Filters, pass a dimension name as the parameter, with comma-separated values. For example
service=AmazonEC2®ion=us-east-1. Usetag=team:platformfor tags. orderBy,desc=true,limit(default 100, max 1000) andoffset.
Common dimensions: date, provider, account, service, region,
resource, chargeCategory, purchaseType, currency, grain,
commitment. An unknown dimension or a limit above 1000 returns 400.
{ "data": { "rows": [ { "dimensions": { "service": "AmazonEC2" }, "measures": { "billedCost": 4200.5, "rowCount": 1830 } } ], "hasMore": false }}The response may also carry notes (advice about the query) and
caveats (what the answer is missing). When you group by resource,
also filter grain=resource. Otherwise service-level rows show up with
an empty resource.
/billing/line-items/refetch Capture a date range again for one account. Runs synchronously. Needs org-wide access.
{ "cloudAccountId": "b1d2…", "provider": "aws", "from": "2026-09-01", "to": "2026-09-08"}{ "data": { "daysRecaptured": 7 }}Here to is exclusive, so one day is from=D, to=D+1.
Invoice Breakdown and Non-Resource Costs
/billing/invoice-breakdown The provider invoice split by charge type and linked account, next to the stored line items for the same window. AWS only. Needs the cloud-account:update permission, org-wide resource view and a cost-capture mode that allows paid calls.
/billing/invoice-issues The invoice documents AWS issued for one account, with the issue date, due date and days after month end. Reads the last 3 closed billing months unless fromMonth and toMonth are given (at most 12 months, none after the current month). AWS only. Needs the cloud-account:update permission, org-wide resource view and a cost-capture mode that allows paid calls. Reads the Invoicing API, not Cost Explorer.
/billing/invoice-reconcile Compares the charge types, services, linked account and days you name with the AWS invoice, and rewrites the stored rows when apply is true. Tax only. AWS only. Same permissions as invoice-breakdown.
Required in the JSON body: cloudAccountId, provider (aws), from and to
(YYYY-MM-DD, to excluded). The window can be at most 31 days.
Optional: linkedAccount (a 12-digit AWS account id) and basis
(cash, the default, or amortized).
Omit linkedAccount to reconcile everything the connected account stores. On a payer
connection, that is the whole payer. A linkedAccount write on a payer connection is
refused when payer-wide Tax is stored.
Each call makes up to five paid Cost Explorer requests, at most $0.05. Do not poll it.
An org in measured_free or modeled_only mode, a missing grant and a rejected key answer 409.
A throttled call answers 503. An unreadable provider response answers 502.
/billing/non-resource-costs Billed cost that no resource owns (tax, support, credits, discounts, commitment fees), by charge type and service. Needs org-wide access.
Required: from and to (YYYY-MM-DD, both included). The window can be at most 366 days.
The rows hold stored cost. Nothing checks them against a provider invoice.
FOCUS 1.4 Dataset
/billing/focus The same billed line items as FOCUS 1.4 Cost-and-Usage rows. Needs org-wide access.
Required: from and to (YYYY-MM-DD). The window can be at most 92
days. limit defaults to 1000 and is capped at 5000. Use offset to
page, and read hasMore to know when to stop.
The response carries focusVersion, rows, conformant, hasMore,
and per-currency totals for the page (totalBilledCost,
includedBilledCost, totalEffectiveCost, includedEffectiveCost).
omitted lists columns the dataset leaves out and why. excluded lists
rows left out and why.
See Cloud Accounts for the full onboarding flow, including the steps before billing verification.