# tounify API > Normalized European electricity tariff and day-ahead price data over a REST API: four `/v2` > endpoints plus an unauthenticated coverage endpoint, JSON, bearer auth. This file is written for > LLM agents integrating against the API. - Base URL: `https://api.tounify.io` - Machine-readable spec: `/openapi/v2.json` (also `/openapi/v2.yaml`) — OpenAPI 3, generated from the live controllers: parameters and schemas follow the code, descriptions are written by hand. Read it for the full parameter and response schemas; this file covers what the schema alone will not tell you. - Human reference: `https://api.tounify.io` (needs JavaScript) ## Getting a token Register at `https://cockpit.tounify.io/register`. A testing token is issued immediately — no credit card, no sales call. Copy it from the Token page. There is no separate test environment. A testing token calls this same API at the same base URL and is served the same data a production token is, so what you validate while evaluating is what you are served once you pay. It is an opaque string beginning `tounify_test_sk_` (a production token begins `tounify_prod_sk_`), not a JWT: nothing in it is readable, so read its expiry from the Token page. A testing token: - is valid for 7 days (renew it on the Token page); - may have one request in flight at a time; - may ask about 5 new things per endpoint per day: the country on `/companies`, the company on `/tariffs`, the tariff on `/versions`, the combination of tariff ids on `/dayahead`. Asking again about something already asked that day is free, so you can vary `include`, `postal_code` or `resolution` around one query; - may make 100 requests per day per account across all endpoints, and 300 per day from one client IP address; - may query 20 different companies (suppliers and network operators) and 20 different tariffs per account in total. Ids you have queried before stay available; the total never resets, and regenerating the token does not reset it; - is refused on the deprecated `/v1` endpoints with a `403`. Evaluate on `/v2`. Daily limits reset at midnight UTC. The allowances are set per account; write to connect@tounify.io to have them raised. So explore deliberately: list first, pick one, then price it. Send the token on every `/v2` request: ``` Authorization: Bearer ``` ## Vocabulary - `{country}` — ISO 3166-1 alpha-2, case-insensitive. `DE` not `GER`, `GB` not `UK`. The accepted set is published as an enum on the `country` path parameter in the spec. - `{sector}` — `consumption` (energy the customer buys), `feedin` (energy they export), or `grid` (the network operator's charge). It is a **path segment**, not a query parameter. - Company ids and tariff ids are opaque short strings (`EWE`, `EWES12MGG`). What an id names comes from where it appears — the company segment of a tariffs listing, or a `*_tariff` parameter — never from the string: companies and tariffs are separate namespaces, and the same string can occur in both (`ENED` is a Dutch supplier and also another Dutch supplier's tariff). Store an id together with its country, its sector and whether it names a company or a tariff. Ids are case-sensitive: send one exactly as a listing returned it (`vatn` is not `VATN`). - A *version* is the day a tariff configuration took effect, formatted `YYYYMMDD`. Passed as `version` on `/dayahead`, it is the day the customer's supply contract was signed: the consumption and feed-in tariffs are priced in the configuration in effect on that date — the latest version on or before it, else the oldest. The grid tariff is always priced as of today, except in GB, where the network cost is part of the supplier's price and follows `version` too. A GB supply price is served with one version per Ofgem cap quarter, each carrying that quarter's own network charge taken back out, so `version` prices the supply and network legs in the same quarter. Without `version` every tariff is priced as of today. The response does not say which version it applied: compare your date with the versions `/versions` lists. A date before the oldest one is priced in that oldest version, which took effect after it. A regulated price that changes for every customer on the same day, such as France's Tarif Bleu, is not fixed by a contract: omit `version` for it, or it is priced as of the signing date instead of today. ## Reaching a price takes three calls A tariff belongs to a company, so listing tariffs requires the company id in the path. ```bash # 1. Which suppliers exist? curl -H "Authorization: Bearer $TOKEN" \ https://api.tounify.io/v2/DE/consumption/companies # 2. Which tariffs does one of them offer? (company id in the path — this is the step most # integrations get wrong by omitting it) curl -H "Authorization: Bearer $TOKEN" \ https://api.tounify.io/v2/DE/consumption/EWE/tariffs # 3. What does that tariff cost at this address? curl -H "Authorization: Bearer $TOKEN" \ "https://api.tounify.io/v2/DE/dayahead?consumption_tariff=EWES12MGG&postal_code=10115&include=fees,vat" ``` The listings are the household catalogue: grid tariffs for commercial or demand-metered connections, and supplier products published for business customers only, are not listed, and no `/v2` route returns their ids. An id your integration already stores keeps pricing. Withheld is not the same as held, and `GET /public/country-stats` is how you tell them apart: its counts are of the whole holding, so a sector whose count equals what that market's listings return has nothing withheld behind them — and therefore no commercial or demand-metered id to pass, whether or not you already store one. In the Netherlands `tariffs.grid` is exactly the connection bands the grid listings return, all of them small-user bands, so no Dutch commercial network tariff is held. A fourth endpoint lists the historic versions of a tariff: ``` GET /v2/{country}/{sector}/{tariff}/versions ``` ## Getting the price right This is where a technically valid call still returns the wrong number. - **The consumption tariff is the bare energy price wherever a network layer exists** — even where suppliers sell one all-in price, as in Great Britain. The network layer is added from a `grid_tariff` you name or from a `postal_code` that resolves the operator (where the regulator sets one national network price, it is added regardless). Add `include=fees,vat` too, to get what a customer actually pays. - **`include` takes `fees`, `vat`, or both**, comma-separated; any other value is a `400`. Omitting them understates the price. `vat` is taken on the components in the same response, so `include=vat` without `fees` also leaves out the VAT on the levies: ask for both. - **On a spot-linked tariff, `energy` is not the exchange price.** A dynamic product sells the day-ahead price through its own price formula, and the result is inside `energy` with no component separating the exchange price from what the supplier adds. Where the formula only adds a per-kWh margin — the spot products held in Germany, Finland and the Netherlands, and most in Austria — reconciling `energy` against EPEX, Nord Pool or a regulator's published day-ahead series leaves the same difference on every hour, negative hours included: that difference is the margin, it differs per tariff, and it is not a data error. Where the formula also scales the index, the difference moves with the price: an Italian variable offer applies the network-loss uplift to the index as well as to the spread, and several Belgian products bill a coefficient times Belpex plus a constant. Reconcile those against the supplier's own formula, not against a constant. - **In a multi-zone market the bidding zone comes from the tariff, not from the address.** Norway clears five day-ahead zones (NO1–NO5), Sweden four (SE1–SE4) and Denmark two (DK1/DK2), and a supplier there sells one spot product per zone and files one tariff for each — often named only by a trailing digit. `postal_code` does not select among them and does not check them: pass a tariff for the wrong zone and you get a `200`, the address's own `grid` and `fees` over another zone's energy price, and nothing in the response naming either zone. The zones diverge by more than the whole retail energy component and can differ in sign on the same hour, so the wrong one is a wrong price that looks entirely plausible. Pick the id for the zone your customer's address is in, and pin that choice in your own tests. - **In Great Britain the network region comes from the tariff too, and it is also inside `energy`.** GB is one bidding zone but fourteen distribution regions, and a supplier sells one product per region and files one tariff for each — the trailing letter of a GB supplier tariff id is that region, and the ids are otherwise identical, as are the names. Because GB suppliers quote one all-in price per region, the stored `energy` is that region's published rate with that region's network charge taken back out, so a region mismatch is wrong on both legs at once. Since 2026-09-24 it is a `400` naming both regions and the row to send instead: pair a tariff for one region with a `postal_code` in another and the request is refused rather than answered with one region's carve-out over another region's charge. Served, it summed to a rate no supplier published — measured 2026-09-24 on Octopus's half-hourly product, the half hour from 19:00Z priced 40.69 p/kWh exc VAT where the supplier published 42.20 p in the South West (the tariff asked for) and 36.26 p in Yorkshire (where the address was), 12% over. Resolve the region from the address once and send that region's tariff id; to price a region deliberately, omit `postal_code` and pass that region's `grid_tariff`. - **In Belgium the region comes from the tariff, and it moves the clock and sometimes the price.** A Belgian supplier publishes its products per region — Flanders, Wallonia and Brussels-Capital — and files one tariff for each, with the region in the product name and one letter of the id (ENGIE's `ENGIF…`, `ENGIW…` and `ENGIB…`). The name is not a field to match on: ENGIE's rows name their region in their own Dutch or French since 2026-09-24, but other suppliers word it their own way (Octa+'s Flemish rows read *Flandre …*), and no response carries the region as a field. Pair a per-region product with a `postal_code` in another region and the request is refused: a `400` naming both regions, whether the rows are ENGIE's or another supplier's (Mega.be, Octa+, TotalEnergies, DATS24). A tariff filed without a region is priced at any Belgian address. At some suppliers the region moves the energy price itself — Octa+'s September 2026 Eco Fixed bills 22.88 c€/kWh at peak in Flanders and 24.04 in Wallonia. At ENGIE the per-kWh energy may well match — ENGIE publishes one national Empower price across all three regional cards — so a price that looks right is not evidence the region is. What differs is the **time-of-use clock**, which each region sets and which the tariff carries: measured 2026-09-25 at `postal_code=5000` (Namur), `ENGIWDR` switches four times a day on Wallonia's own windows — ENGIE's Walloon card prints *Hochtarifzeit: von 7 bis 11 Uhr und von 17 bis 22 Uhr* and the same windows at weekends — while `ENGIFDR` at that address switched twice on the Flemish clock and billed the peak register of 0.16398 €/kWh straight through Wallonia's 11:00–17:00 off-peak window, against 0.11814: six hours a day at +0.0458 €/kWh, and the off-peak register all Saturday where the Walloon card charges peak. Pick the product for your customer's region. - **`GB` is Great Britain, and a Northern Ireland address is not in it.** England, Scotland and Wales are one market; Northern Ireland is in the all-island Single Electricity Market, with its own regulator, its own network operator and its own suppliers, and no country code here covers it. A `BT` postal code is accepted and resolves no operator, so the response is a `200` carrying a Great Britain supplier's price with no `grid` component — the whole network layer missing, and from 1 October 2026 the wrong VAT rate as well, since the temporary zero rate on domestic electricity covers Great Britain only while Northern Ireland stays at 5%. Filter `BT` addresses out before you call; the response will not do it for you. - **A levy the network operator collects is in `grid`, not in `fees`.** `fees` carries what the address is billed apart from the network charge; a statutory per-kWh levy that the operator collects inside its own published network rate stays inside `grid`, because that rate is what the operator bills and splitting it would double-count. Norway is the case to know: the Energifondet levy is inside `grid` while the electricity duty is in `fees`. Reconcile a network invoice against `grid + fees` together — per layer it is off in both directions and the sum is right. - **`grid` is one number covering every per-kWh network charge the market regulates**, transmission and distribution together, even where the bill prints them as separate lines set by two different operators and the regulator sets them in two separate decisions. Greece is the plainest case: the served `grid` is the transmission charge (ΧΧΣ) plus the distribution charge (ΧΧΔ), and there is no request or response shape that splits them back apart. Reconciling against an invoice means summing the invoice's network lines, not matching one of them. Where the scope is stated at all it is stated in the grid tariff's `name`, which is the operator's own and in the market's own language (`Χρεώσεις Χρήσης Συστήματος & Δικτύου (ΧΧΣ + ΧΧΔ)`, `Tariffa TDM domestica (TRAS/DIS/MIS)`): do not expect a grid tariff's `description`, which is `null` in almost every market. - **Some network tariffs are an opt-in that no address can select.** An operator's listing carries every tariff it files, and a market may regulate products the customer chooses per connection rather than ones the address determines. Germany's § 14a EnWG modules for controllable devices — a heat pump, a wallbox, a home battery — are the case to know: Modul 2 is a reduced flat rate and Modul 3 a three-band time-variable one, each conditional on the customer having opted in and, for Modul 3, on a smart meter and on not being load-profile metered. `postal_code` alone resolves the operator's ordinary household row, so such a household priced that way is priced on the wrong product, silently. Resolve the operator first — `/dayahead` without `grid_tariff`, or `/grid/companies?postal_code=` — then pass **that** operator's module id as `grid_tariff`; an id belonging to an operator that does not serve the address is priced as asked and never checked against it. Two further things to test for. A module the operator bills in only some quarters — German operators may restrict Modul 3 to as few as two of the four — is served its ordinary rate outside them, so a flat 24 hours is that tariff's own behaviour and not a missing band; compare two dates half a year apart before concluding the bands are unmodelled. And the device rows an operator filed before the § 14a modules existed (`Entnahmestelle Wärmepumpe`, `Entnahmestelle Elektromobilität` and their equivalents) are still listed and still priced, while being closed to connections commissioned from 1 January 2024 and usually requiring an individual agreement. In Germany those rows say so in their `description`, alone among grid tariffs anywhere: the reduced charge is the pre-2024 § 14a regime, a device commissioned since then takes a module instead, and an existing control agreement is billed this way only until 31 December 2028. A `null` on a German device row means only that its own sheet does not state the restriction — most of those sheets have not been read for it, and a few print a device rate under a different, still-current legal basis — so read the operator's own price sheet, which the tariff's `link` points at, before choosing one. - **Two of an operator's household rows are not comparable on `grid` alone.** Where an operator files more than one household row, `postal_code` selects one of them and the response does not mark that a choice was made — `grid_tariff` names the tariff priced, never how it was reached. The rows are normally different **tariff structures** rather than competing prices for the same thing, and the one selected is the structure most households in that market are on. Flanders is the case to know: each Fluvius area files a digital-meter row and an analogue-meter row, and at Fluvius Imewo the digital row's `grid` is 0.0522864 €/kWh against the analogue row's 0.0839581, 60.6 % apart (measured 2026-09-23). Neither is wrong and the difference is not a 60 % saving: Flanders bills a digital meter partly on a **capacity tariff**, 54.20 €/kW/year on the average of the twelve monthly quarter-hour peaks with a 2.5 kW floor, and an analogue meter on a flat 135.50 €/year instead — and **no v1 or v2 response carries either**, because both are priced per kW or per year rather than per kWh. Over a year the two land within about 4 % of each other. So do not read a per-kWh gap between an operator's rows as a price difference, do not pick the cheaper-looking one, and add the non-kWh legs yourself from the sheet the tariff's `link` points at. Pass `grid_tariff` to name the row your customer's meter is actually on. - **A Swedish `grid` is the regulator's standard household customer, not your customer.** Swedish grid tariffs are Energimarknadsinspektionen's type-customer filings rather than the operator's price list. A postal code resolves the *Villa 16A, 5 000 kWh/år* standard customer, or *Lägenhet 16A, 2 000 kWh/år* where the operator left the villa column blank, with the tariff's `name` saying which. A household on a 20 A or 25 A fuse is one of up to four further rows per operator — *Villa 20A, 10 000 kWh/år*, *Villa 20A, 20 000 kWh/år*, *Villa 25A, 20 000 kWh/år*, *Villa 25A, 30 000 kWh/år* — listed by `GET /v2/SE/grid/{company}/tariffs` and never chosen by a postal code: pass the one closest to your customer as `grid_tariff`. It matters: most operators charge the same per-kWh rate at every fuse, but some do not — E.ON Energidistribution's 16 A rate is almost three times its 20 A one — and at Bodens Energi Nät, Luleå Energi Elnät and PiteEnergi Elnät a 20 A or 25 A household pays **nothing** per kWh, its whole network charge being the annual fixed one, which this response does not carry. An operator's time-of-use product, Vattenfall's *tidstariff* among them, has no row: the regulator's filing publishes a second band's rate for some larger-fuse customers but never the clock that switches to it, so a customer on one is served a flat rate in every interval with nothing marking it, and an operator that files only such a blend for a standard customer has no row for it. The exception is an operator whose row was read from its own price sheet — Nacka Energi and Skövde Energi Elnät are priced on a låglast/höglast rate switching weekdays 06:00–22:00 from November to March. Add the fixed annual charge yourself. - **`postal_code`** resolves the grid operator serving the address: it adds that operator's `grid` component, selects operator- or location-specific fees, the address's time-of-use switching times and any address-specific VAT rate. Without it, only country-wide fees apply. Where several operators divide one postal code, one is selected and nothing in the response marks it: the one covering most of the code where that can be told — in Switzerland the one holding most of the code's official building addresses — and otherwise the one whose id sorts first, which says nothing about the address. In Switzerland that tie-break is reached only where the address figures cannot separate the operators, almost always two serving the identical set of municipalities, and the network charge and the municipal levy both follow whichever is picked. `grid/companies?postal_code=` lists the same single operator. Where your customer's municipality lies on such a boundary, name its operator's tariff with `grid_tariff`. Operator-specific levies follow the operator whose grid tariff is priced — so a passed `grid_tariff` moves them with it, and a municipal levy is then that operator's rate at this postal code; do not add the address's own levies on top. Send it as your customer writes it: case, spaces, hyphens and a leading tag naming the path's own country are ignored (`1094HK`, `1094 hk` and `NL-1094 HK` are one code). The code is never checked against the path's country: one tagged with another country (`DE-10115` on `/NL/`) is a `400`; one of another country's shape without a prefix maps to no operator — send each address under its own country. Only the part a market's operators are mapped on is used — the four digits in the Netherlands, the outward code in Great Britain (`SW1A` of `SW1A 1AA`) — so a code of just that part resolves too. A code that maps to no operator is a `400` in a market whose network price follows the operator (Germany, Austria, the Nordics, the Netherlands, Belgium and the other markets `country-stats` reports a postal map for), naming the code — **unless the market prices the network nationally**, and then the charge is added whatever the address says. That is not a France-only carve-out. Several markets are like this, and in one of them, Greece, `country-stats` reports `postalCodes: 0` while every `/dayahead` call still carries `grid` and a `grid_tariff` nobody asked for. So the absence of `grid` is not a test that an address resolved. **Test the market once rather than the address every time:** call `/dayahead` with neither `grid_tariff` nor `postal_code`; a `grid_tariff` in the response means that market's network price is national and a postal code will never change it. Where no `grid_tariff` comes back, `/v2/{country}/grid/companies?postal_code=…` returning `[]` is the signal that an address resolved no operator. In France the network price is national in exactly this sense: an address served by a local distributor lists no operator on `/grid/companies`, and `/dayahead` still adds the national network charge there. In France a postal code in Corsica or an overseas department is a `400`: VAT there differs from the mainland rate served here. Northern Ireland (`BT` codes on `GB`) and the Azores and Madeira (`9xxx-xxx` on `PT`) are refused the same way: they are markets of their own, not the one served under that country code. So is a postal code that names another country (`CH-6900` sent under `AT`): an address must be in the country of the request. - **A VAT territory smaller than the country is carried only where a rate is held for it**; France, Great Britain and Portugal refuse an address instead. Spain resolves its own: a Canary Islands postal code (`35`, `38`) is served the Canary IGIC and a Ceuta (`51`) or Melilla (`52`) one the IPSI, in `vat` and at the household rate — IGIC 0 % holds only for a dwelling contracted at up to 10 kW, and other Canary supply owes the 3 % no request can ask for. Italy resolves its two: Livigno (`23041`) and Campione d'Italia (`22061`) lie outside the EU VAT territory (Directive 2006/112/EC art. 6) and no local tax replaces it on a supply delivered over a network, so `vat` is 0 at both — and Livigno, outside the Italian excise territory as well, carries no excise in `fees` either, while Campione, inside it since 2020, does. Germany resolves one: Helgoland (`27498`) is named in the sentence that defines each of the two German tax territories (UStG § 1 (2), StromStG § 1), so `vat` is 0 there and `fees` carries no electricity duty — while the two network levies, the § 19 StromNEV surcharge and the municipal concession fee stay, none of them being levied under either statute. Büsingen am Hochrhein (`78266`) is excluded by the same two sentences but takes its electricity from a Swiss operator, so it is not a German address to price at all: it resolves no operator and is refused. Portugal serves one on the country's mainland stack, with a `200` and nothing in the response to mark it: the Azores and Madeira (`9xxx-xxx`) are priced on the mainland access tariff and the mainland IVA rate although both autonomous regions set their own network tariffs and their own lower rates. `GB` serves Northern Ireland the Great Britain rate, which from 1 October 2026 is 0 % while a `BT` address owes 5 % (see the bullet on `GB` above). Confirm the territory before billing an address in any of them. - **`NL` prices the European Netherlands**, and this is the one case no postal code can reach. The Caribbean Netherlands — Bonaire, Sint Eustatius and Saba — is part of the country but its electricity is regulated by the ACM under the Wet elektriciteit en drinkwater BES: billed in US dollars, as a fixed charge per kVA of connection capacity plus a per-kWh tariff, and outside the mainland energy tax. Those islands have no postal codes today, so a request cannot name such an address even to be refused; an `NL` call with no `postal_code` answers on the mainland stack in EUR. Route those addresses away before you call. - **A narrower price still returns HTTP 200.** Omitting `grid_tariff`/`postal_code` or `include=fees` shows only as absent keys (`grid_tariff`, `grid`, `fees`), and a missing operator- or location-specific fee does not show at all. Nor does a `vat` short of those absent layers: it is present, and taken on what the response carries. An empty `postal_code=` is answered as an omitted one. Decide per market what a complete price needs, and assert on those keys in your tests rather than eyeballing the number. - **Sum the components.** A price point carries `energy`, `grid`, `fees` and `vat` separately; the total per-kWh price is their sum. They are deliberately not pre-blended. - **In a bundled market only the sum is a published figure.** Where the supplier publishes one all-in price — every Great Britain tariff, and France's regulated Tarif Bleu — `energy` is that figure less `grid` and `fees`, so it can move hour to hour on a tariff published as a single flat rate: the network share of a flat price does. Reconcile such a market against the sum, never against `energy` alone, and do not add your own network model to it. - **A price here is a rate per kWh, never a bill.** No endpoint described in this file returns a charge that is not per kWh: capacity (per kW) and standing charges, and levies or credits charged per connection or per year, are not in any of these responses. Multiplying the per-kWh total by annual consumption therefore leaves every fixed charge out — in the Netherlands, the whole network charge of the connections served here, and the energy-tax credit per connection. Where a network charge has no per-kWh part, `grid` is a genuine `0` next to the operator's `grid_tariff`; in the Netherlands every connection-size band of an operator prices identically here. That zero is a property of the band, not of the country: above the Dutch small-user boundary of 3x80 A the network charge does carry a per-kWh transport rate, high and low by an operator clock, and no tariff above that boundary is held — so do not read a Dutch `0` as "this market has no per-kWh network cost" for a commercial connection. - **A price here is before any state price support.** A support the state pays against the customer's own hourly consumption is not deducted from any component, because it depends on who the customer is and how much they use. In Norway a household not on Norgespris receives *strømstøtte*: 90 % of each hour's zone spot price above 77 øre/kWh ex VAT (the 2026 threshold), plus 25 % as compensation for VAT where VAT is paid — Nordland, Troms and Finnmark pay none on electricity, so the formula there stops at the 90 % — on its first 5,000 kWh a month, deducted on the network operator's invoice; neither businesses nor holiday homes are covered, because the scheme is for household consumption only. A household that chose *Norgespris* instead has the zone spot hedged to a 40 øre/kWh ex VAT reference price for its first 5,000 kWh a month — 1,000 for a holiday home, the only one of the two schemes a holiday home may have — settled on the same invoice; its supplier's markup and monthly fee stay payable on top, so that reference is not the household's whole energy cost. Neither is in `energy`, `grid` or `fees`, so in any hour when spot is above the threshold the sum of the components is above what a Norwegian household pays net — by more than half of it on a high-price day. Apply the scheme yourself for a household customer. - **`fees` is one rate per kWh, at no particular volume.** No annual consumption is taken, so a levy's consumption bands cannot be applied: in the Netherlands `fees` carries the energy tax on the first 10,000 kWh a year, and consumption above that is taxed at lower statutory rates you apply yourself. - **In Switzerland `energy` and `grid` are the regulator's reference-household rates.** ElCom publishes every Swiss operator's price per standard consumption profile; the rates here are those of profile H4 (4,500 kWh a year), with the fixed annual charges taken out. Where an operator's per-kWh rate varies with annual volume, or blends a day and a night rate that is not published separately, the figure is exact at 4,500 kWh a year and differs for other households — in either direction, and by several percent in some municipalities. No consumption profile can be requested. - **`fees` is priced for household supply.** No customer class is taken, so a levy set per class comes at its household rate: in Germany a business connection's municipal concession fee is far below the household one `fees` carries. That fee is set per municipality within statutory caps keyed to its population; `fees` carries the rate of the operator `postal_code` resolves where Tounify holds it, and otherwise — including without a `postal_code` — the **lowest** of those household caps, so that the figure is never above what a municipality is allowed to charge. Where the address's own rate is higher, and a large city's is the highest, `fees` is low by the difference. - **A time-of-use price follows a reference clock where the market sets one per meter.** In France the off-peak hours are assigned to each delivery point by the network operator, and a reform is moving part of them into the early afternoon; the price here is on the 23:00–07:00 off-peak window, for both the supply and the network component, whatever the address. A product with its own clock (Tempo, 22:00–06:00) keeps it on `energy` while `grid` stays on the network's window — the meter records the two separately. No subscribed power is taken either: France's Base tariff is priced at its 3–6 kVA rate. In France `fees` is the electricity excise only; the pension-scheme contribution is charged on the fixed part of the bill, which is not served. - `resolution` is in **seconds**: `3600` (default), `1800` or `900`. A coarser one than a price changes at returns each interval's time-weighted average, so an hour spanning a quarter-hour tariff switch blends the two rates. `historic_days` is a whole number of days before today, 0 to 3; the series covers today and tomorrow in the country's local time. - **The local day is one IANA time zone per country, and the response does not say which.** Every price point is `from_utc`, a UNIX instant, and the day the series covers is bounded in the country's mainland zone. Two markets have postal codes in a second time zone and are served the mainland day anyway, an hour before their own: Spain's Canary Islands (`Atlantic/Canary`) and Portugal's Azores (`Atlantic/Azores`). Re-bucket per address there. And do not assume 24 points to a day: **daylight saving** makes a European local day 23 or 25 hours long on the last Sundays of March and October — days `historic_days` cannot reach, so test that path against your own fixtures. - **The series ends on a delivery day, not on your day.** Every price source served here publishes one whole **delivery day** at a time, and every one of them runs that day on Central European time — the instant that is 00:00 in `Europe/Berlin` and 23:00 in `Europe/London`. So the far edge of the window is that instant, not the market's own midnight. A market an hour behind CET is an hour short of its own today until its next delivery day is published: one point at `resolution=3600`, two at 1800, four at 900. In Great Britain, whose spot products publish late in the afternoon, that is most of the day. A market an hour ahead (Estonia, Finland) already carries the first hour of its tomorrow from local midnight. A CET market lands exactly. Poll at `next`, and bucket the points by their own `from_utc`: an array of 25 is not a 25-hour day, and an array of 23 is not a missing price. - Prices are per kWh, in the country's major currency. `energy`, `grid` and `fees` are always net of VAT; `include=vat` adds VAT as its own `vat` component, on consumption prices only. ## When tomorrow's prices appear, and when to call again `/dayahead` serves today and tomorrow in the country's local time. Tomorrow is not ours to publish: each market's source — a day-ahead exchange, a regulator, or the supplier itself for a product priced per half hour — publishes it once a day on its own clock, and it appears here once that publication has been read in. `next` names the later of those two moments, which is the one a caller actually has to wait for. - **Until it lands the series simply stops.** A call made before tomorrow has been published returns `200` with a shorter series — today's prices, ending at the last point the source has published. No field distinguishes that from a complete answer: there is no as-of timestamp and no completeness flag, so count the points you got, or compare the last `from_utc` with the day you need, before scheduling anything against them. A short series is not an error, and it is not the same thing as no prices at all: that case is the `500` described under *Errors*, and it does not resolve by retrying either. - **A late publication is retried, not skipped.** When a publication is due and the series does not carry it yet — an exchange result that reaches its data platform late, which happens — `next` is a retry a few minutes out instead of the following day's publication, and stays one until the publication lands. Following `next` is enough on a late day too. - **A publication is a window, not a calendar day.** Where a source publishes for a window that ends partway through the next local day, that day stays short of its last hours until the source publishes again — Octopus publishes its half-hourly GB product for the 23 hours ending 23:00 London, so a complete GB day is 46 half-hourly points while it is tomorrow and 48 once the following publication has landed. Do not read the missing tail as a price of zero. - **`next` is a recommendation, and deliberately not the same value twice.** It carries a random offset of up to 30 minutes on top of that publication moment, drawn again on every request, so that clients following the advice do not all arrive in the same second. Two identical requests therefore return values up to half an hour apart; the field cannot be asserted on in a test, cached as a fact, or compared between two clients, and polling exactly at `next` can be up to half an hour later than the data. Schedule from it anyway — a fixed interval either misses a late publication or spends calls on nothing — and if you need the prices the moment they exist, poll from `next` minus thirty minutes. - **A tariff with no price feed has no publication.** For a static price, `next` is 07:00 in the market's local time every day: a daily check-in, not a moment anything is published. Its prices change only when a new version takes effect, which `/versions` lists. - **The `ETag` on a `/v2` response is not a validator you can use.** It is a hash of the whole body, `next` included, so it differs on every call and `If-None-Match` never answers `304`. There is no conditional request to make on `/v2`; schedule from `next` instead. ## Before you authenticate ``` GET /public/country-stats ``` No token required. Returns, per country, how many companies and tariffs exist per sector, how many postal codes resolve to a grid operator, and whether regulatory fee data is available. Both counts are of what is held rather than of what the listings show: a tariff the household catalogue leaves out is counted, and so is a company whose every tariff it leaves out, so `companies.consumption` can exceed the length of `/v2/{country}/consumption/companies` — and does wherever a market has suppliers selling to business customers only. `companies.total` counts suppliers, not companies: the distinct companies with a consumption or a feed-in tariff, never a network operator, which are a separate register and are counted in `companies.grid` alone. `feeCoverageComplete` says the market's statutory per-kWh levies are settled — either rows are held, or the market provably levies none on a household, which is why it can be `true` beside `hasFees: false`. It is a statement about the market, not about your customer: it does not promise that every levy is priced for the volume, the customer class or the address you are pricing, and the limits on `fees` under *Getting the price right* still apply. Greece is the case to know — `feeCoverageComplete: true` while its public-service levy is banded on four-monthly consumption, which no request here carries, so a heavy household is charged the first band. `hasLocationScopedFees` says at least one of those rows is scoped to an address, so a price asked in that market without `postal_code` is short a fee or carries the country VAT rate where the address does not. A country the `country` enum accepts but this response does not list holds nothing at all. Being listed is not the converse: a country is here once anything is held for it, so an entry counted `0` in every sector is a market whose fee answer is settled and whose catalogues are not built yet. A sector counted `0` for a country holds none there yet, and that sector's listings return an empty array with `200`. No currency is reported, because it does not vary within a market: every price is in the market's own national currency, which each `/dayahead` response names in `currency` as an ISO 4217 code. Every market is EUR except `CH` (CHF), `CZ` (CZK), `DK` (DKK), `GB` (GBP), `HU` (HUF), `NO` (NOK), `PL` (PLN), `RO` (RON) and `SE` (SEK). ## Errors - `400` — unknown country or sector; an id that does not exist, or that names something else — a company where a tariff belongs, a tariff where a company belongs, a tariff of another sector, or an id that differs from a real one only in case (the message says which); a malformed value (`available` other than true or false, `type` other than dynamic or static, an `include` value other than fees and vat, a `version` that is not YYYYMMDD, a `historic_days` that is not a whole number from 0 to 3, a `resolution` other than 3600, 1800 or 900); and, on `/dayahead` only, a tariff belonging to a different country than the path or a query parameter the route does not define. The listing routes ignore an undefined parameter. - `401` — missing or malformed `Authorization` header, or an unknown or revoked token. The `WWW-Authenticate` header says which: `Bearer realm="tounify"` alone for no credential, `error="invalid_request"` for a malformed header, `error="invalid_token"` for a token that is not accepted. A production token is valid until revoked on the Cockpit Token page; hold two while rotating. Regenerating the testing token retires its old value at once. - `403` — no active subscription, or a testing token that has expired or used up its total company or tariff allowance. In the last case the body carries a `testingLimit` block naming what ran out; that allowance never resets. - `429` — testing tokens only: another request from the token is still in flight, or a daily limit is reached. Only the limit on new things per endpoint carries `rateLimit.resetAt` (and the `X-RateLimit-Reset` header); read that rather than retrying on a fixed interval. - `500` — the price series could not be produced: no price at all is published yet for the tariff and period (a period published only in part is a `200` whose series ends at the last published point), the time-of-use switching times are not available for the location, or the tariffs cannot be combined. The identical request returns the same result until the prices are published; quote the `X-Request-Id` response header when you contact support. An unknown company or tariff id is a `400`, never a `404`; a `404` means the path does not exist. So is an id from another country than the path, and one in the wrong sector or slot (a consumption tariff passed as `feedin_tariff`, a supplier on a `grid` route): the message names the country the id belongs to, or what the id names instead. ## Versioning `/v2` is current. `/v1` is deprecated, still served for existing integrations, and should not be used for new work.