---
title: "Generate utility insights for a year"
method: POST
path: "/utility/insights"
---

# Generate utility insights for a year

`POST /utility/insights`

Builds the year's facts and anonymous supply-point profiles, asks the AI gateway for insights and switching-saving ranges (Irish electricity and gas only; percentages only, never prices or suppliers), validates the answer and caches it per data and price book. A cached answer for unchanged data is returned without calling the gateway. Free: no AI credits are charged. Stop with POST /utility/insights/{requestId}/cancel.

## Request body

- UtilityInsightsRequest
  - `requestId` string, required — The frontend's UUID for this request, which its Stop names.
  - `year` integer, required

## Response `200`

Insights

- UtilityInsightsResponse
  - `data` UtilityInsights, required
    - `facts` UtilityInsightFact[], required
      - `compareValue` number, double — What value is compared with - the previous year for yoy_change and baseline_deviation, last year's share for share_shift, last year's kWh for projected_annual.
      - `id` string, required
      - `kind` 'yoy_change' | 'projected_annual' | 'share_shift' | 'baseline_deviation' | 'coverage' | 'unassigned_rows' | 'gross_bills', required
      - `month` string — YYYY-MM
      - `resource` string
      - `unit` string, required — pct, kWh, months, rows or bills.
      - `value` number, double, required
    - `generatedAt` string, date-time, required
    - `insights` UtilityInsight[], required
      - `citedFactIds` string[], required
      - `id` string, required
      - `kind` 'trend' | 'anomaly' | 'data_quality' | 'switching', required
      - `supplyPointRef` string
      - `text` string, required — Prose with numbers only as {{factId}} tokens.
    - `priceBookAsOfMonth` string — YYYY-MM of the price book the ranges are based on.
    - `savingsAvailability` 'available' | 'no_active_book' | 'book_stale', required
    - `stale` boolean, required — The utility data or the active price book changed since these were generated.
    - `status` 'ready', required
    - `suggestions` UtilitySavingSuggestion[], required
      - `confidence` string, required — medium or high.
      - `reasonCode` 'night_heavy_profile' | 'high_standing_charge' | 'high_unit_rate' | 'contract_likely_expired', required
      - `resource` 'electricity' | 'natural_gas' | 'lpg' | 'heating_oil' | 'gas_oil' | 'diesel' | 'petrol' | 'water' | 'waste' | 'heat_steam' | 'other', required
      - `savingPctHigh` integer, required
      - `savingPctLow` integer, required — Whole-percent lower bound; 0 or below reads "up to savingPctHigh%".
      - `supplyPointLabel` string, required — "Electricity supply 1"-style label; never an MPRN/GPRN.
      - `supplyPointRef` string, required
    - `year` integer, required

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `404` — Utility insights are not enabled
- `409` — The request was stopped by the user
- `502` — The AI gateway failed or answered invalidly
- `503` — The AI gateway is not configured or unavailable
- `504` — The AI gateway took too long

## Changes

- **2026-10-01** `b4751fd15397` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/greentally/apis/esgai-api/changes/utility/insights/post.md)

---

[API](https://skmtc.dev/greentally/apis/esgai-api.md) · [All operations](https://skmtc.dev/greentally/apis/esgai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/greentally/apis/esgai-api/revisions/b4751fd15397?raw)
