Atlas Inference

Usage export

Row-level metered usage, one row per request, in JSON or CSV.

GET /v1/usage/export returns the underlying usage rows rather than aggregates — one row per request, each carrying the price that was stamped on it. It exists so metering accuracy can be checked outside the product, before any billing depends on it.

curl "https://api.inference.runatlas.com/v1/usage/export?format=csv&start=2026-09-01&end=2026-10-01" \
  -H "Authorization: Bearer $ATLAS_READ_KEY" \
  -o atlas-usage-september.csv

Authenticates with a console session or a read-scoped key. It accepts the same start, end, model, and api_key_id filters as GET /v1/usage, with the same 93-day period ceiling.

Two formats, one row definition

?format=csv

Streamed as text/csv, walked with an internal cursor and written as it goes, so a full month does not have to be held in memory at either end. The filename is set from the organization and period.

CSV does not accept a cursor — it paginates internally and returns the whole period in one response. Passing one is refused with cursor_not_supported.

Both formats are generated from a single row definition, so a figure that reconciles in one reconciles in the other. The columns array in the JSON response is the CSV header, in the same order.

The columns

Reconciling it yourself

The prices are on every row precisely so the cost columns can be recomputed rather than believed:

input_cost  == backend_reported_input_tokens  / 1e6 * input_price_per_mtok
output_cost == backend_reported_output_tokens / 1e6 * output_price_per_mtok

Three things to get right when you do:

  1. Do not add backend_reported_reasoning_tokens to the output figure. It is already inside it.
  2. Price on backend_reported_*, not on generated_ or delivered_. The generated and delivered figures answer "what happened to the stream", not "what was metered".
  3. Do not reprice with today's published price. Rows written before a price change carry the older price, and that is intentional.

Cursors

A JSON cursor encodes a position — a timestamp and a request id — and nothing about who is reading. A cursor handed to another account selects a position in their data, which is to say nothing of yours. An unparseable cursor is refused with invalid_cursor.

Rows are ordered by occurred_at then request_id, so paging is stable even as new rows arrive behind you.

On this page