Formitra

Forecast API

Read stored forecasts. Requests do not run models.

OpenAPI schema (JSON) — import into an API client or use to generate a client. The schema contains no keys or forecast data.

Authentication

Use the supplied API key in an HTTP header. Dashboard email/password login is separate. Do not put keys in URLs.

curl --fail-with-body -H "Authorization: Bearer $FORMITRA_API_KEY" \
  "$FORMITRA_BASE_URL/v1/gb/demand/latest"

Set FORMITRA_BASE_URL to this website's origin and FORMITRA_API_KEY to your private pilot key. Do not share the key.

Endpoints

GET pathResult
/v1/gb/demand/latestForecast for the currently due issue date, when available on time.
/v1/gb/demand/vintagesStored issue summaries. Optional inclusive issued_from and issued_to dates (YYYY-MM-DD); limit 1–366, default 30.
/v1/gb/demand/vintages/{identifier}Stored issue by date (YYYY-MM-DD), including late/unavailable records.
/v1/gb/demand/performance.csvPerformance CSV for forecasts confirmed available on time, with partial or complete observed demand.

CSV scopes: full (pooled models), daily (per issue), hourly (local delivery hour), calendar (overlapping slices), matched and daily_matched (all three curves on identical half-hours with NESO forecasts published at or before the input cutoff). partial and partial_matched are separate per-issue scopes for observed half-hours only, not full-window results; expectedPeriods gives the full window size for these rows. MAE, RMSE, bias and maxError are MW; coverage80/coverage90 are marginal fractions; blank means unavailable. periods counts half-hours and windows counts distinct issues. RMSE is calculated from pooled squared errors, not averaged daily RMSE. An empty archive returns a header only. modelReleaseGroup identifies the exact pair of model releases (family, version and manifest hash); legacy issues stay separate. Results are never pooled across release groups. Dashboard users can download the same file via the private dashboard.

Forecast format

Daily windows run from 23:00 Europe/London on the issue date until 23:00 the next day. There are 46, 48 or 50 half-hours at DST. periods gives UTC start/end, local labels and settlement identifiers. tracks.independent and tracks.assisted contain aligned median, lower80, upper80, lower90 and upper90 MW arrays. Independent excludes NESO forecast channels; assisted uses available pre-issuance NESO information alongside demand history, weather and calendar inputs to predict the full window. neso and nesoPublishedAt are aligned arrays; null means missing NESO input, not zero demand or a missing model prediction. Missing NESO inputs remain missing; available values may influence model predictions across the window. Later NESO releases are not backfilled into a frozen forecast.

nesoCoverage.available / nesoCoverage.expected counts frozen NESO inputs over all delivery periods: for example, 12/48 NESO inputs can accompany 48/48 assisted model predictions. Performance's same-period comparison uses only observed periods with eligible NESO values, and applies that identical subset to both models and NESO. It is not a whole-window NESO score.

inputCutoff is the latest allowed input time; generatedAt is when the forecast was computed; scheduledIssue is its publication deadline. Source and model hashes identify the data and model used. Failed issues may omit curves. Experimental intervals describe per-period uncertainty, not guaranteed whole-window or holiday coverage.

Before the deadline a computed curve may be served with provisional=true. This means availability has not yet been independently confirmed. A separate check must retrieve the complete forecast before the deadline to confirm on-time publication. publishedAt records when that check finished, not a guarantee of uninterrupted availability. After the deadline, latest returns 503 unless that confirmation has been saved. A brief 503 is possible while it becomes visible.

Status and errors

Latest returns 503 if the due forecast is absent, late or unavailable; it does not silently substitute an older issue. Before 07:30 local the due issue is yesterday. 401 means missing/invalid key; 404 means unknown vintage; 422 means invalid parameters; 429 means rate limited (Retry-After: 60). Private responses are not cacheable. The shared pilot limit is 120 private requests/minute. No production SLA.