Skip to main content
The exporter is a single program you run in your own environment. It reads a provider’s bill, converts it to FOCUS 1.2, and pushes it to CostGraph. Your provider credentials stay with you; only the FOCUS rows leave. Use it when you would rather not hand us a credential, when the bill sits somewhere we cannot reach, or when your provider publishes a FOCUS export you already have. It is the same code CostGraph runs when it pulls for you, so the data lands identically either way.

Before you start

  1. Open Settings -> Integrations and choose FOCUS push. Pick the tenant the charges belong to, and copy the connection id (fpc_...).
  2. Open Settings -> API keys and create a key with the focus:write scope. Add deployment:register as well if you will run the container, which pulls the image from our registry.
One connection carries one provider. Exporting two providers means two connections.

Run it

The container runs once and exits, reading the current month. Schedule it with cron, a systemd timer, or your orchestrator; pass --month YYYY-MM to backfill a past one.

Settings

A setting is read from a flag, then a config file, then the environment, so any of the three works and the more specific one wins. Credentials are usually environment variables; everything else reads well in a file, at --config, ./focus-exporter.yaml, or /etc/focus-exporter/config.yaml:
Each provider’s variables are listed on its own integration page, and all of them together in the provider reference.

Reading a bill from storage

Some providers do not answer a billing API at all; they write the bill to storage on a schedule. AWS Data Exports writes Parquet to S3, Azure Cost Management writes to Azure Blob Storage, and STACKIT publishes part_000X.csv.gz to its own Object Storage. The objectstore provider reads all of them. Point it at where the bill is: You do not normally set OBJECTSTORE_KIND: it is inferred from the endpoint (an .blob.core.windows.net host is Azure, a file:// path is a directory, anything else is S3). Set it only to be explicit. OBJECTSTORE_LAYOUT answers one question: given all the files in the bucket, which ones make up a billing period? A provider does not always write one tidy file per month. Prefer manifest where the export publishes one: nothing is guessed from file names, and a run that lands while the exporter is reading cannot be read half-written. .csv, .csv.gz and .parquet are all read.

What a run does

  1. Works out which files or API calls cover the window you asked for.
  2. Reads them, repairs the deviations from FOCUS we know about, and drops rows that are not FOCUS at all, naming each one it drops.
  3. Pushes in pages, each carrying its position in the run, so a page that has to be retried replaces itself rather than duplicating.
  4. On the last page CostGraph builds the window.
A run holds no state, so a failed run is re-run rather than repaired. Pushing a month again replaces it rather than doubling it, which is what makes a daily schedule over the running month safe.

What it needs

  • Outbound HTTPS to CostGraph and to your provider. Nothing inbound.
  • Read-only credentials. The exporter never writes to your bucket or your provider.
  • Memory in proportion to the largest file, and only for Parquet, which cannot be read as a stream. CSV of any size is read as it goes.