solarwhen.com

Free hourly solar forecast for any UK postcode. No API key. No signup. JSON.

Quick start

curl 'https://solarwhen.com/forecast/SW1A?dir=s&tilt=35&kwh=4.5'

Replace SW1A with your postcode outcode (the part before the space).

Try it

GET /forecast/{outcode}

{outcode} is the first part of a UK postcode — e.g. SW1A, EC1Y, N1.

Param Type Default Description
dir enum s Panel facing: n / ne / e / se / s / sw / w / nw
tilt 0 – 90 35 Panel tilt in degrees from horizontal
kwh number System size in kWp. Presence flips default mode to kwh.
mode percent | kwh percent (kwh if kwh given) Output units: percent of nameplate or absolute kWh.
when today | now | tomorrow today Window: today (00–23 local), now (rolling 24 h from this hour), tomorrow.
region A–P auto-derived from outcode DNO region letter for the Agile price lookup. Override only if you're in a postcode-area-split edge case.

Response

{
  "date":              "2026-05-08",       // local date the window starts on
  "region":            "C",                // DNO region used for the Agile price lookup
  "solar_production":  "medium",           // low | medium | high (peak as % of nameplate)
  "electricity_price": "normal",           // cheap | normal | expensive (window's average vs Agile baseline)
  "sunrise":           "05:24",            // local time HH:MM (null at polar latitudes)
  "sunset":            "20:52",
  "peak":              { "hour": "14",     // best solar-generation hour
                         "kwh":  2.0 },    // or "percent" in percent mode; null if no daylight
  "total_kwh":         15.8,               // only present in kwh mode
  "average_price":     22.4,               // avg Agile p/kWh across the 24 h window
  "hourly_pv": {                            // PV production: kWh (1 dp) or % (integer)
    "00": 0.0, "01": 0.0, ...
    "14": 2.0, "15": 2.0, ...
    "23": 0.0
  },
  "hourly_price": {                         // Agile p/kWh per hour (1 dp)
    "00": 12.3, "01": 8.5, ...              // missing days fall back to the previous day
    "23": 18.7
  }
}

Rate limits

100 requests / minute and 5 000 requests / day per IP. Every response carries:

RateLimit:        limit=100, remaining=99, reset=59
RateLimit-Policy: 100;w=60, 5000;w=86400

On a hit, the API responds 429 with a Retry-After seconds header.

Status codes

200Success
400Bad input (invalid outcode format, tilt out of range, unknown dir / mode / when).
404Outcode not in the UK postcode list.
429Rate limit hit. Wait the Retry-After seconds.
503Forecast batch not yet refreshed for this hour. Try again shortly.

How it works