Connect your providers
Custom sources
Bring in the bill of any vendor CostReveal has no connector for, as FOCUS files you upload or send with a key, and explain it like any other spend.
A custom source brings in the bill of a vendor CostReveal has no connector for, such as Mistral or Cohere. You send it files in FOCUS, the FinOps Foundation's open format for billing data, and its spend is explained, budgeted, allocated and reported like any other.
Each vendor is its own custom source, and each counts as one connection on your plan.
Set one up
- In CostReveal, go to Connections and, under Custom sources, choose Add source.
- Enter the vendor's name as its bill names it, such as
Mistral AI, and choose Save. - Send it a file: choose one under Send a FOCUS file, or send it from your own systems as shown below. Download the template gives a file with the columns already named.
Each file is kept exactly as sent and read within a minute. Under Files sent, each one says which billing periods it stated, how many lines it added and restated, and which rows it left out and why.
What a file needs
A file is CSV or Parquet, up to 64 MB uncompressed, with one row per charge. Name each column exactly as FOCUS does.
| Column | Required | What it holds |
|---|---|---|
BilledCost | Yes | What the vendor billed for the row, as a plain decimal such as 12.40. |
BillingCurrency | Yes | The currency of BilledCost, as an ISO 4217 code such as USD or EUR. |
BillingPeriodStart | Yes | The first day of the billing period the row is billed in, such as 2026-09-01. |
ChargePeriodStart | Yes | The day the charge began, such as 2026-09-14. |
ChargeCategory | Yes | Usage, Purchase, Tax, Credit or Adjustment. |
BillingAccountId | Yes | The vendor's account, organization or workspace the row is billed to. |
BillingAccountName | No | That account's name. |
SubAccountId | No | A finer account within it, such as a project; it names the account when present. |
ServiceName | No | What was bought, such as a model family or a product. |
SkuMeter | No | What was measured, such as Input tokens. |
ConsumedQuantity | No | How much of it. |
ResourceId | No | The resource that used it, such as an API key or a workspace. |
RegionId | No | Where it ran. |
ChargeClass | No | Correction for a row that corrects an earlier billing period. |
InvoiceId | No | The invoice the row is on. Rows without one are shown as not yet invoiced. |
Tags | No | A JSON object of tags, such as {"team":"search"}, read with the project's keys. |
Dates are ISO 8601, in UTC. Amounts carry no currency symbol and no thousands separator.
The template, with one example row:
BilledCost,BillingCurrency,BillingPeriodStart,ChargePeriodStart,ChargeCategory,BillingAccountId,BillingAccountName,ServiceName,SkuMeter,ConsumedQuantity,ResourceId,InvoiceId,Tags
12.40,USD,2026-09-01,2026-09-14,Usage,org-1234,Example organization,Example API,Input tokens,4130000,workspace-search,,"{""team"":""search""}"
How a file changes your figures
Each billing period a file has rows for becomes exactly what the file says:
- A row not recorded before is added.
- A row whose amount changed is restated, pointing at what it corrects.
- A row the file no longer has is restated to zero, once.
Periods the file has no rows for stay as they are. So send a billing period whole, and to correct it, send it again in full. Nothing is ever edited or deleted: every change is a new line, and the history of what was sent before is kept.
Sending the newest file again changes nothing, so a retried upload is safe. Sending an older file again makes its periods what that file says once more.
A file is refused, with nothing recorded, when a required column is missing, it is not valid CSV or Parquet, or none of its rows can be read. A row without a date, an amount, a known currency or an account is left out and counted; the rest of the file is read.
Send files from your own systems
Under Settings, API keys, create a key of the project with the scope Send data only. It can send files and usage data to its project and read nothing, so it is safe to keep in a scheduled job. Then send each file to the custom source's address, shown under Send files from your own systems:
curl -X POST "<the address shown in Connections>?name=2026-09.csv" \
-H "Authorization: Bearer <your key>" \
-H "Content-Type: text/csv" \
--data-binary @2026-09.csv
- Send CSV as
text/csv, and Parquet asapplication/vnd.apache.parquet. - Add
Content-Encoding: gzipto send a file compressed. The 64 MB limit is on the file uncompressed. nameis optional; it is how the file is listed.- The answer is
202 Accepted, with the file as it was received. Read the outcome withGETon the same address, which lists the 100 most recent files, newest first.
How spend is explained
- Service is the file's
ServiceName, so it is DIRECT. A row without one is shown under its charge category. - Team, feature and customer come from
Tags, read with the project's tag keys, and from allocation rules that match the custom source, its services or its accounts. - Model is not read: FOCUS has no column for one.
Spend that nothing names is shown as unknown, never spread across teams.
How figures are checked
Every line is recorded exactly as the file states its billed cost, and attribution must add up to it on every dimension. A custom source has no second source to compare with, so CostReveal says that every amount is attributed rather than that the vendor's total agrees.
Removing a custom source
Removing it under Connections deletes every figure its files brought in from the project, and the files themselves within a day. The audit log keeps a record of the removal, and of every file sent.