
# Per-request metadata

Every successful response from the gateway carries a top-level
`lowrouter_metadata` field:

```json
{
  "id": "chatcmpl-...",
  "choices": [...],
  "usage": {...},
  "lowrouter_metadata": {
    "provider": "openai",
    "region": "eu-west",
    "energy_wh": 0.0021,
    "carbon_gco2e": 0.00057,
    "carbon_intensity_gco2_per_kwh": 270,
    "estimation_methodology": "ecologits-calculated",
    "routing_mode": "auto",
    "routing_reason": "lowest_carbon_intensity",
    "fallback_occurred": false,
    "providers_attempted": ["openai"]
  }
}
```

Two kinds of values appear in this block, and they don't carry the
same weight:

- **Recorded** — facts about the routing decision LowRouter itself
  made: `provider`, `region`, `routing_mode`, `routing_reason`,
  `fallback_occurred`, `providers_attempted`, `requested_alias`. The
  region is the one whose endpoint we called; what that guarantees
  about data residency beyond the routing itself is defined by the
  upstream provider's own terms.
- **Estimated** — modeled numbers: `energy_wh`, `carbon_gco2e`,
  `carbon_intensity_gco2_per_kwh`. Produced per the
  [methodology](../sustainable-ai/methodology) from annual grid
  averages, and absent rather than fabricated when we can't classify
  the request.

## Field reference

### `provider`

The upstream that actually served the request. Matches an `id` in
`GET /providers` (a discovery endpoint) and the provider segment of a
model ID.

### `region`

The region the upstream served from. Strings like `eu-west`,
`us-east`, `us-west`. The region is the one encoded in the resolved
model ID's locode.

### `energy_wh`

Total energy estimated for the request, in watt-hours. Computed from the resolved
model's per-token energy coefficients and the request's token counts.
See [methodology](../sustainable-ai/methodology).

### `carbon_gco2e`

Total CO₂e estimated for the request, in grams. Derived from
`energy_wh`, the data-center overhead (PUE 1.20), and the grid
intensity for the serving region.

### `carbon_intensity_gco2_per_kwh`

The grid carbon intensity used for the serving region, in grams of
CO₂e per kWh.

### `estimation_methodology`

Identifies how the estimate was produced (e.g. an EcoLogits-based
calculation). Present when an estimate was made.

### `routing_mode`

`auto` when the router chose the route for you (an
`auto/<creator>/<model>` request), `explicit` when you named the
provider and region yourself.

### `routing_reason`

Why the router landed where it did. For an auto-routed request this is
one of `eu_sovereign_preferred`, `lowest_carbon_intensity`,
`lowest_cost`, `round_robin`, or `only_route`. See [routing](routing).

### `fallback_occurred`

`true` if the route changed after selection. LowRouter does not
silently substitute providers — an explicit ID is a pin and an
auto-routed request commits to the winner of its ranking — so this
reads `false` on current traffic. It stays on the response, and in
your usage export, because historical rows can carry `true`.

### `providers_attempted`

The list of providers tried for this request, in order.

### `requested_alias`

Present only when the request addressed a
[model alias](aliases) (`"model": "alias/big"`). Carries the alias as
sent (`alias/big`), while the response's top-level `model` field
carries the full model ID the alias resolved to. Absent on
non-aliased requests.

## Worked scenario: "why did this request go to us-east?"

Your dashboard shows one row served from `us-east` in a week of
otherwise-EU traffic. The metadata of that response answers it without
guesswork:

```json
"lowrouter_metadata": {
  "provider": "openai",
  "region": "us-east",
  "routing_mode": "auto",
  "requested_auto": "auto/openai/gpt-4.1",
  "routing_reason": "lowest_carbon_intensity",
  "eu_sovereign": false,
  "providers_attempted": ["openai"]
}
```

Read it as a trace: you sent `auto/openai/gpt-4.1`, so the route was
LowRouter's to choose, and `eu_sovereign: false` says plainly that no
sovereign route existed for that model — auto-routing prefers
EU-sovereign providers in EU/EEA regions, but falls through rather
than failing when a model has none. `routing_reason` then names what
decided among what was left. Nothing was misrouted, and nothing was
silently substituted: `providers_attempted` lists one provider.

If a US route is unacceptable for that workload, this is the signal to
move it from `auto/` to a pinned model ID or an [alias](aliases): an
explicit route fails loudly instead of falling back outside your
constraint. See [routing](routing) for the pinning syntax.

## Headers

The gateway sets an `X-Request-ID` header on every response. Use it to
correlate a request with your own logs or when reporting an issue.

## Streaming

For streamed requests, `lowrouter_metadata` arrives on the **final
chunk** (the one before `[DONE]`), carrying the same fields as the
non-streaming block. Earlier chunks don't include it. See
[first completion → streaming](../getting-started/first-completion).

## When metadata is partial

The eco fields (`energy_wh`, `carbon_gco2e`,
`carbon_intensity_gco2_per_kwh`) can be absent when:

- The resolved model's parameter count is unknown and we'd rather omit
  the number than fabricate one.
- The request consumed no tokens (e.g. a non-completion response).
- The upstream returned an error mid-stream that prevented usage
  accounting.

When they're missing, the dashboard shows the row with a `—` for the
carbon column and a note linking to the methodology page. The routing
fields (`provider`, `region`, `routing_mode`, …) are still present.

## Privacy

The `lowrouter_metadata` block contains nothing about prompt or
response content — only the resolved route and the metric estimates. It
is safe to log on the client side; we do.
