
# Usage accounting

Every request through the gateway produces a record. This page is the
schema and the access patterns.

## Per-request record

The fields stored for each request:

| Field | Description |
|-------|-------------|
| `generation_id` | Opaque, globally unique. Returned in the response and used to look up the record later. |
| `created_at` | UTC timestamp when the gateway accepted the request. |
| `completed_at` | UTC timestamp when the response was fully sent (post-streaming for streamed requests). |
| `key_id` | The virtual key used. Names are joined in for display. |
| `requested_model` | The string the caller sent (e.g. `lowrouter/auto`). |
| `resolved_model` | The model the router actually picked. |
| `provider` | Upstream provider that served the request. |
| `region` | Region the upstream served from. |
| `prompt_tokens` | Token count of the input. |
| `completion_tokens` | Token count of the output. |
| `total_tokens` | Sum. |
| `latency_ms` | First-byte latency for streaming, end-to-end for non-streaming. |
| `cost_credits` | Credits debited for this request. |
| `eco.energy_wh` | Estimated energy for the inference, in watt-hours. |
| `eco.carbon_g` | Estimated CO₂e for the request, in grams. |
| `eco.carbon_per_1k_tokens_g` | Same number, normalised per 1K tokens. |
| `eco.accuracy` | `accurate` / `medium` / `gross` confidence band. |
| `eco.methodology_version` | Version of the formula and data inputs that produced these numbers. |
| `status` | `ok`, `client_error`, `upstream_error`. |
| `routing_trace` | Which providers were considered, which one was picked, why. |

Prompt and response *content* are not stored.

## Where to read it

- **Dashboard → Recent transactions** — the last ~50 requests, with
  filtering by date range, model, provider, region, key.
- **Transaction detail page** — full record, accessed by clicking a row
  or by visiting `/dashboard/transactions/{generation_id}`.
- **API**: [`GET /api/v1/generation/{id}`](../api-reference/overview)
  returns the same record as JSON. Useful for programmatic queries,
  reconciliation, or piping into your own data warehouse.
- **Export** — **Dashboard → Recent transactions → Export** produces a
  CSV of the filtered range, capped at 50,000 rows per export.

## Aggregates

The dashboard pre-computes a small set of aggregates and updates them
on each request:

- Tokens per day, per model.
- Cost per day, per model.
- Energy and carbon per day, per model.

These aggregates power the charts. They are derived from the
per-request records and are reproducible from a CSV export.

## Retention

| Data | Retention |
|------|-----------|
| Per-request records | 13 months from `created_at`. |
| Daily aggregates | 36 months. |
| Audit log entries | 36 months. |
| Account profile | For the lifetime of the account. |

After retention expires the per-request rows are deleted and replaced
by anonymised aggregates. Aggregates are kept for sustainability
reporting and platform analytics; they cannot be used to reconstruct
individual requests.

You can request earlier deletion of all your usage records via the
support email; the deletion is irreversible and may affect your
ability to dispute past invoices.

## Reconciliation tips

- The sum of `cost_credits` over a day should equal the daily cost on
  the dashboard within a fraction of a credit (rounding).
- The sum of `total_tokens` over a day grouped by model is what the
  upstream provider's usage report (if you have one) should show.
- The carbon estimate is reproducible: given the same `resolved_model`,
  `region`, and `total_tokens`, recomputing with the formula in
  [methodology](../sustainable-ai/methodology) using the
  `methodology_version` should yield the same gram count.

If the numbers diverge more than rounding allows, that is a bug —
[open an issue](https://github.com/carbonifer/lowrouter/issues).
