Most people searching for a Nord Pool API want one thing: the day-ahead price for a Nordic or Baltic zone, in code, every day. That number does not have to come from Nord Pool. Here is what the paid API gives you, what the free route gives you, and code that works.
Not from Nord Pool itself: automated access to Nord Pool data is a paid, licensed product. The public website shows current and recent prices for people to read, not for software to collect.
But the day-ahead auction Nord Pool runs is the single European day-ahead coupling (SDAC), and its results for every bidding zone are published by ENTSO-E on the Transparency Platform — free, with an API token you request by e-mail. For day-ahead prices in SE1–SE4, NO1–NO5, DK1–DK2, FI, EE, LV and LT the numbers are the same. We checked that on 25 September 2026 against two independent sources and all averages matched to the cent.
| Data | ENTSO-E | Nord Pool |
|---|---|---|
| Day-ahead zone prices | free | paid |
| In NOK, SEK, DKK | EUR only | paid |
| System price | — | paid |
| Intraday, order book | — | paid |
| Load, generation | free | partly |
Standard library only. Replace the token, change the dates, run. The start and end are in UTC: the Nordic delivery day 25 September 2026 runs from 22:00 UTC the day before.
import urllib.request
import xml.etree.ElementTree as ET
TOKEN = "your-entso-e-token"
ZONES = {"SE1": "10Y1001A1001A44P", "SE2": "10Y1001A1001A45N", "SE3": "10Y1001A1001A46L",
"SE4": "10Y1001A1001A47J", "NO1": "10YNO-1--------2", "NO2": "10YNO-2--------T",
"NO3": "10YNO-3--------J", "NO4": "10YNO-4--------9", "NO5": "10Y1001A1001A48H",
"DK1": "10YDK-1--------W", "DK2": "10YDK-2--------M", "FI": "10YFI-1--------U",
"EE": "10Y1001A1001A39I", "LV": "10YLV-1001A00074", "LT": "10YLT-1001A0008Q"}
def day_ahead(eic, start, end): # start/end in UTC, e.g. "202609242200"
url = ("https://web-api.tp.entsoe.eu/api?securityToken=" + TOKEN +
"&documentType=A44&in_Domain=" + eic + "&out_Domain=" + eic +
"&periodStart=" + start + "&periodEnd=" + end)
root = ET.fromstring(urllib.request.urlopen(url).read())
ns = {"n": root.tag.split("}")[0].strip("{")}
series = root.find("n:TimeSeries", ns) # first series only: some zones send a duplicate
period = series.find("n:Period", ns)
points = sorted((int(p.find("n:position", ns).text), float(p.find("n:price.amount", ns).text))
for p in period.findall("n:Point", ns))
n = 96 if period.find("n:resolution", ns).text == "PT15M" else 24
prices = []
for i, (pos, price) in enumerate(points): # curve A03: a repeated price is sent once
nxt = points[i + 1][0] if i + 1 < len(points) else n + 1
prices += [price] * (nxt - pos)
return prices
for zone, eic in ZONES.items():
p = day_ahead(eic, "202609242200", "202609252200") # 25 Sep 2026, CEST
print(zone, len(p), "quarter hours, average", round(sum(p) / len(p), 2), "EUR/MWh")Output for 25 September 2026: SE3 121.62, FI 62.75, EE 112.56, LV and LT 172.07 EUR/MWh — the same as Elering and elprisetjustnu.se publish. A ready-made version is on GitHub as nordpool-day-ahead, and today’s prices are on our Nord Pool day-ahead prices page.
The token, request limits and empty responses are covered in our ENTSO-E API guide; every zone code is in the EIC code list.
If you work in pandas anyway, the entsoe-py library does the same in three lines and handles the traps above. Zone names are short codes such as SE_3 or NO_1:
import pandas as pd
from entsoe import EntsoePandasClient # pip install entsoe-py
client = EntsoePandasClient(api_key="your-entso-e-token")
start = pd.Timestamp("2026-09-25", tz="Europe/Stockholm")
end = pd.Timestamp("2026-09-26", tz="Europe/Stockholm")
se3 = client.query_day_ahead_prices("SE_3", start=start, end=end)
We build price and fundamentals pipelines on ENTSO-E and the Nordic TSOs — with the gaps filled, every version kept and alerts when a feed goes quiet.
Get in touch