{"openapi":"3.0.0","paths":{"/v2/{country}/{sector}/companies":{"get":{"description":"The companies with a tariff in this sector: suppliers for consumption and feed-in, network operators for grid. This is the household catalogue, so a supplier that sells only to business customers is not listed.","operationId":"listCompanies","parameters":[{"name":"country","required":true,"in":"path","description":"Two digit country code (ISO 3166-1 alpha-2), e.g. `DE` not `GER` and `GB` not `UK`. Case-insensitive. A code outside this list is a 400. A code in it that GET /public/country-stats does not list holds no data yet. Being listed there is not the converse: a country is in that response 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.","schema":{"enum":["AT","BE","BG","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GB","GR","HR","HU","IE","IT","LT","LU","LV","MC","MT","NL","NO","PL","PT","RO","SE","SI","SK"],"type":"string"}},{"name":"sector","required":true,"in":"path","description":"Which side of the meter to price: `consumption` (energy your customer buys), `feedin` (energy they export) or `grid` (the network operator's charge). A sector a country holds no data for yet — counted 0 in GET /public/country-stats — lists as an empty array.","schema":{"enum":["consumption","feedin","grid"],"type":"string"}},{"name":"postal_code","required":false,"in":"query","description":"Customer postal code. On the grid sector it returns only the operator serving that address — where several operators divide one postal code, the one covering most of it, and where the map cannot tell which covers more the one whose id sorts first — which says nothing about the address, and in Switzerland is a code whose operators serve the very same municipalities, which no measure of territory can separate. It is also the one GET /{country}/dayahead prices the address on (coverage per country: GET /public/country-stats). The list is empty where the address is not mapped yet, and also where the operator serving it files no grid tariff of its own — where one national network price applies to every operator, only the operator that files it is listed, while GET /{country}/dayahead prices the address on that same national tariff. Ignored on consumption and feed-in, where suppliers operate nationwide — which is not the same as one price nationwide: where a country clears its day-ahead market in several bidding zones, a supplier sells one spot product per zone and files one tariff for each, so the listing is complete and the choice between them is made on the tariff id, not on the address. Case, spaces, hyphens and a leading tag naming the path's own country are ignored; in NL only the four digits of a Dutch four-digits-and-two-letters code are used, in GB the outward code. The postal code is never checked against the path's country: a code tagged with another country (`DE-10115` on `/NL/`), or one of another country's shape, is not refused — it maps to no operator and is answered as any unmapped code is. Send each address under its own country.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CompanyDTO"}}}}},"400":{"description":"Unknown `country` (not a supported ISO 3166-1 alpha-2 code) or unknown `sector`. A query parameter the route does not define is ignored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":400,"message":"Invalid country 'UK' in param"}}}},"401":{"description":"Missing `Authorization: Bearer <token>` header, a malformed header, or a token that is unknown or revoked. The `WWW-Authenticate` response header says which: `Bearer realm=\"tounify\"` alone when no credential was sent, `error=\"invalid_request\"` for a malformed header, `error=\"invalid_token\"` for a token that is not accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":401,"message":"Unknown or revoked token"}}}},"403":{"description":"The token is recognised but not entitled to this request: the subscription is not active; or the testing token has expired (regenerate it on the Cockpit Token page).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicForbiddenErrorDTO"},"example":{"statusCode":403,"message":"Token is not entitled to this request"}}}},"429":{"description":"Testing tokens only: another request from the same token is still running (send them one after another), or a daily limit is reached. Only the daily limit on new things asked about on this endpoint carries the `rateLimit` block. The limits are listed under *Rate limits* in the introduction.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRateLimitErrorDTO"},"example":{"statusCode":429,"message":"Request limit exceeded","error":"Too Many Requests","rateLimit":{"limit":5,"remaining":0,"resetAt":"2026-08-07T00:00:00.000Z"}}}}}},"security":[{"bearer":[]}],"summary":"List energy companies","tags":["v2"]}},"/v2/{country}/{sector}/{company}/tariffs":{"get":{"description":"A company's tariffs, for your customer to choose from. This is 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 on GET /{country}/dayahead. Tariffs no longer offered are included unless you pass `available=true`. What the catalogue holds is a separate question from what this route lists: a product is held only where its published price can be stated exactly, and one whose shape cannot be held is refused rather than approximated, so it has no row and nothing distinguishes it from a product the company does not sell. The refusal is per sector — a plan whose export rate steps on the volume exported in a day is held as a consumption tariff and has no feedin row — so an empty answer on one sector says nothing about the other.","operationId":"listTariffs","parameters":[{"name":"country","required":true,"in":"path","description":"Two digit country code (ISO 3166-1 alpha-2), e.g. `DE` not `GER` and `GB` not `UK`. Case-insensitive. A code outside this list is a 400. A code in it that GET /public/country-stats does not list holds no data yet. Being listed there is not the converse: a country is in that response 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.","schema":{"enum":["AT","BE","BG","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GB","GR","HR","HU","IE","IT","LT","LU","LV","MC","MT","NL","NO","PL","PT","RO","SE","SI","SK"],"type":"string"}},{"name":"sector","required":true,"in":"path","description":"Which side of the meter to price: `consumption` (energy your customer buys), `feedin` (energy they export) or `grid` (the network operator's charge). A sector a country holds no data for yet — counted 0 in GET /public/country-stats — lists as an empty array.","schema":{"enum":["consumption","feedin","grid"],"type":"string"}},{"name":"company","required":true,"in":"path","description":"ID of the company","schema":{"example":"CID1","type":"string"}},{"name":"type","required":false,"in":"query","description":"Only tariffs of this type: `dynamic` when the price comes from a published series and can change every interval, `static` when it is a fixed price per period — including a rate computed from a market average, which is `static` even though it is re-struck between periods, and a time-of-use tariff, which is `static` even though its rate changes during the day on a fixed repeating clock. The `type` property of the returned tariff carries the full definition. Any other value is a 400.","schema":{"enum":["dynamic","static"],"type":"string"}},{"name":"available","required":false,"in":"query","description":"`true`: only tariffs the source still publishes. `false`: only the tariffs in this catalogue the source has stopped publishing. Neither answers who may take a tariff — one still published can be closed to new customers; see `available` on the returned tariff. The catalogue does not hold every closed tariff a company still bills its existing customers on, so an empty list does not mean the company has none. Any other value is a 400.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicTariffDTO"}}}}},"400":{"description":"Unknown `country` or `sector`, a `company` id that does not exist, belongs to another country, or names a tariff or a company of the other kind — a grid operator on a supplier route, or the reverse (the message says which), a `type` other than `dynamic` or `static`, or an `available` other than `true` or `false`. A query parameter the route does not define is ignored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":400,"message":"No company found for id CID1"}}}},"401":{"description":"Missing `Authorization: Bearer <token>` header, a malformed header, or a token that is unknown or revoked. The `WWW-Authenticate` response header says which: `Bearer realm=\"tounify\"` alone when no credential was sent, `error=\"invalid_request\"` for a malformed header, `error=\"invalid_token\"` for a token that is not accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":401,"message":"Unknown or revoked token"}}}},"403":{"description":"The token is recognised but not entitled to this request: the subscription is not active; the testing token has expired (regenerate it on the Cockpit Token page); or the testing token has reached its total of different companies or tariffs — the body then carries `testingLimit`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicForbiddenErrorDTO"},"example":{"statusCode":403,"message":"Token is not entitled to this request"}}}},"429":{"description":"Testing tokens only: another request from the same token is still running (send them one after another), or a daily limit is reached. Only the daily limit on new things asked about on this endpoint carries the `rateLimit` block. The limits are listed under *Rate limits* in the introduction.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRateLimitErrorDTO"},"example":{"statusCode":429,"message":"Request limit exceeded","error":"Too Many Requests","rateLimit":{"limit":5,"remaining":0,"resetAt":"2026-08-07T00:00:00.000Z"}}}}}},"security":[{"bearer":[]}],"summary":"List tariffs","tags":["v2"]}},"/v2/{country}/{sector}/{tariff}/versions":{"get":{"description":"The versions of a tariff, newest first. A version is the day a tariff configuration took effect; pass one as `version` on GET /{country}/dayahead. A tariff no longer offered keeps its versions, and GET /{country}/dayahead keeps pricing it. A supplier that re-issues a product under a new dated code (an Octopus fixed product in GB, every few weeks) adds a version: without `version` the tariff prices the issue on sale today, and the day the customer signed prices the issue they signed. Where the source gives every issue its own code, each issue is its own tariff instead, not a version: in IT a monthly re-issue of an offer (A2A's PLACET offers, every month) is listed as a second tariff under the same name, the earlier one `available: false` and still priced by GET /{country}/dayahead. There, store the id of the issue the customer signed; `version` does not choose between issues.","operationId":"listTariffVersions","parameters":[{"name":"country","required":true,"in":"path","description":"Two digit country code (ISO 3166-1 alpha-2), e.g. `DE` not `GER` and `GB` not `UK`. Case-insensitive. A code outside this list is a 400. A code in it that GET /public/country-stats does not list holds no data yet. Being listed there is not the converse: a country is in that response 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.","schema":{"enum":["AT","BE","BG","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GB","GR","HR","HU","IE","IT","LT","LU","LV","MC","MT","NL","NO","PL","PT","RO","SE","SI","SK"],"type":"string"}},{"name":"sector","required":true,"in":"path","description":"Which side of the meter to price: `consumption` (energy your customer buys), `feedin` (energy they export) or `grid` (the network operator's charge). A sector a country holds no data for yet — counted 0 in GET /public/country-stats — lists as an empty array.","schema":{"enum":["consumption","feedin","grid"],"type":"string"}},{"name":"tariff","required":true,"in":"path","description":"ID of the tariff","schema":{"example":"TID1","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TariffVersionsDTO"}}}}},"400":{"description":"Unknown `country` or `sector`, or a `tariff` id that does not exist, belongs to another country, or names a company or a tariff of another sector (the message says which). A query parameter the route does not define is ignored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":400,"message":"No tariff found for id TID1"}}}},"401":{"description":"Missing `Authorization: Bearer <token>` header, a malformed header, or a token that is unknown or revoked. The `WWW-Authenticate` response header says which: `Bearer realm=\"tounify\"` alone when no credential was sent, `error=\"invalid_request\"` for a malformed header, `error=\"invalid_token\"` for a token that is not accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":401,"message":"Unknown or revoked token"}}}},"403":{"description":"The token is recognised but not entitled to this request: the subscription is not active; the testing token has expired (regenerate it on the Cockpit Token page); or the testing token has reached its total of different companies or tariffs — the body then carries `testingLimit`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicForbiddenErrorDTO"},"example":{"statusCode":403,"message":"Token is not entitled to this request"}}}},"429":{"description":"Testing tokens only: another request from the same token is still running (send them one after another), or a daily limit is reached. Only the daily limit on new things asked about on this endpoint carries the `rateLimit` block. The limits are listed under *Rate limits* in the introduction.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRateLimitErrorDTO"},"example":{"statusCode":429,"message":"Request limit exceeded","error":"Too Many Requests","rateLimit":{"limit":5,"remaining":0,"resetAt":"2026-08-07T00:00:00.000Z"}}}}}},"security":[{"bearer":[]}],"summary":"List tariff versions","tags":["v2"]}},"/v2/{country}/dayahead":{"get":{"description":"Price series for a consumption, feed-in and/or grid tariff — supply at least one. Consumption and feed-in come back as two separate series. A grid tariff is priced on the consumption series only, as its `grid` component, so a feed-in and a grid tariff without a consumption tariff return no grid prices.\n\nEvery consumption tariff is the bare energy price. The `grid` component comes from `grid_tariff`, from `postal_code`, or — where the grid price is set nationally — without either; with none of them the response has no `grid` component and understates the price. In GB the supplier's published price includes its network and policy costs, which are returned as `grid` and `fees`: a GB price is complete only with `postal_code` and `include=fees`.\n\nEvery component is per kWh and nothing is pre-summed. Capacity (per kW) and standing charges, and levies or credits charged per connection or per year, are not in this response: a price here is a per-kWh rate, never a bill. Nor is a state price support paid against the customer's own consumption deducted: Norway's household strømstøtte (90% of each hour's zone spot above 77 øre/kWh ex VAT in 2026, plus 25% VAT compensation where VAT is paid — Nordland, Troms and Finnmark pay none — on the first 5,000 kWh a month) and its alternative Norgespris (the zone spot hedged to a 40 øre/kWh ex VAT reference, with the supplier's markup still payable on top) are both settled on the network invoice after the tariff, so in an hour above the threshold a Norwegian household pays net less than the sum of these components. Where a network charge has no per-kWh part, `grid` is 0 — every Dutch connection band served here is that case. That 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, and no tariff above that boundary is held, so a 0 never says a commercial connection has no per-kWh network cost.\n\nIn CH `energy` and `grid` are the rates the regulator ElCom publishes for its reference household, consumption 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, that 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.","operationId":"getDayAheadPrices","parameters":[{"name":"country","required":true,"in":"path","description":"Two digit country code (ISO 3166-1 alpha-2), e.g. `DE` not `GER` and `GB` not `UK`. Case-insensitive. A code outside this list is a 400. A code in it that GET /public/country-stats does not list holds no data yet. Being listed there is not the converse: a country is in that response 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.","schema":{"enum":["AT","BE","BG","CH","CY","CZ","DE","DK","EE","ES","FI","FR","GB","GR","HR","HU","IE","IT","LT","LU","LV","MC","MT","NL","NO","PL","PT","RO","SE","SI","SK"],"type":"string"}},{"name":"consumption_tariff","required":false,"in":"query","description":"ID of the consumption tariff, from GET /{country}/consumption/{company}/tariffs — a tariff id such as `EWES12MGG`, not a company id such as `EWE`.","schema":{"maxLength":32,"example":"ETID1","type":"string"}},{"name":"feedin_tariff","required":false,"in":"query","description":"ID of the feed-in tariff, from GET /{country}/feedin/{company}/tariffs.","schema":{"maxLength":32,"example":"FTID1","type":"string"}},{"name":"grid_tariff","required":false,"in":"query","description":"ID of the grid tariff, from GET /{country}/grid/{company}/tariffs. Usually left out: `postal_code` selects the serving operator's tariff. When passed, `include=fees` follows it too: operator-specific levies are the named tariff's operator's, at the postal code given, not those of the operator the postal code resolves — do not add the address's own levies on top. In a country without grid tariffs a passed id is ignored without being checked. In some markets one connection can be billed under more than one network regime, and which one is a contractual fact about the customer that no address implies: Germany files the §14a EnWG controllable-device modules as grid tariffs of their own — Modul 2 a flat reduced working price, Modul 3 a three-level daily clock — beside the operator's ordinary household tariff and beside the older device tariffs (Wärmepumpe, Speicherheizung, Elektromobilität) that operators still publish for devices commissioned before 1 January 2024 under an individual agreement. A connection that chose no module is billed Modul 1, the ordinary household tariff plus a flat annual credit that no per-kWh rate carries, so it is not a grid tariff of its own. `postal_code` alone resolves the operator's ordinary household tariff; pass the id of the regime your customer is on, and read the operator's own price sheet (`link` on the tariff) for what each one requires.","schema":{"maxLength":32,"example":"GTID1","type":"string"}},{"name":"version","required":false,"in":"query","description":"The day the customer's supply contract was signed, as YYYYMMDD — typically a date from GET /{country}/{sector}/{tariff}/versions. 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. In GB a supply price has one version per Ofgem cap quarter, each served with that quarter's own network charge taken back out, so `version` prices the supply and network legs in the same quarter. Omit it and every tariff is priced as of today. Any other format is a 400. The response does not name the version applied: compare with GET /{country}/{sector}/{tariff}/versions — a date before the oldest version is priced in that oldest one. 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.","schema":{"example":"20230228","type":"string"}},{"name":"historic_days","required":false,"in":"query","description":"Whole days before today to include, 0-3 (default 0). The series covers today and tomorrow in the country's local time; tomorrow's prices appear once published. Any other value is a 400. Nothing older is served, and `version` changes which tariff configuration prices the window, never where the window lies: to reconcile an invoice for an earlier period, store each day's series once it is published and reconcile against what you stored. The day boundary is computed in one IANA time zone per country — the mainland zone, which the response does not state — so in the two markets whose postal codes reach a second zone the window is displaced by an hour: an address in Spain's Canary Islands (`Atlantic/Canary`) or Portugal's Azores (`Atlantic/Azores`) is served the peninsular day, which starts an hour before its own local midnight. Do not assume a day is 24 points either: at the European daylight-saving change a local day is 23 or 25 hours long, and the last Sundays of March and October are outside the window this parameter reaches. The far edge of the series is the end of the last published **delivery day**, and every price source served here runs delivery days on Central European time — the instant that is 00:00 in `Europe/Berlin` and 23:00 in `Europe/London`. A market an hour behind CET is therefore an hour short of its own today — one hour of points, however many the `resolution` you asked for puts in one — until the next delivery day is published (Great Britain), and a market an hour ahead already carries the first hour of its tomorrow from local midnight (Estonia, Finland); a CET market lands exactly on its own day. Poll at `next`, and bucket the points by their own `from_utc` rather than by the length of the array.","schema":{"example":2,"type":"number"}},{"name":"include","required":false,"in":"query","description":"Extra per-kWh components, comma-separated: `fees` (regulatory levies and surcharges; operator- or location-specific ones need `postal_code`; nothing is added where the country has none) and `vat` (VAT on the sum of the other components in this response, consumption series only — so `include=vat` without `fees` leaves out the VAT owed on the levies as well as the levies; ask for `fees,vat` for the tax a customer pays). Any other value is a 400.","schema":{"type":"array","items":{"type":"string","enum":["fees","vat"]}}},{"name":"resolution","required":false,"in":"query","description":"Price interval in seconds: 3600 (default), 1800 or 900. A coarser interval averages the source prices; a finer one repeats them. What counts as the source interval is the tariff's own settlement interval, not the market's, and two tariffs in one market can differ: an hourly-settled spot product returns its hour four times at `resolution=900`, because that hour is what each quarter of it is billed at, while a quarter-hourly product returns four different prices. Asking for 900 is therefore not by itself a way to find out which kind you are on.","schema":{"enum":[3600,1800,900],"type":"number"}},{"name":"postal_code","required":false,"in":"query","description":"Customer postal code, in the country of the request: a code naming another country (`CH-6900` on AT) is a 400, and so is one in a territory served as a market of its own — Corsica and the French overseas departments, Northern Ireland (`BT`) on GB, the Azores and Madeira (`9xxx-xxx`) on PT. It selects the grid operator serving the address (coverage per country: GET /public/country-stats): with `consumption_tariff` and no `grid_tariff`, that operator's charge is added as `grid`. Where several operators divide one postal code, or a market's operator map is held at a coarser administrative level than the code, the operator covering most of it is the one selected — in Switzerland the one holding most of the code's official building addresses — and where the map cannot tell which covers more, the one whose id sorts first, which says nothing about the address: in Switzerland that is a code whose operators serve the very same municipalities, where no measure of territory can separate them, and the network charge and the municipal levy both follow whichever is picked. It is a choice the response does not mark, because `grid_tariff` names the tariff priced and not how it was reached. Pass `grid_tariff` to price a named operator's tariff instead of the one the code resolves — which is also how to reach a second tariff of the operator the code does resolve, since an operator filing several household rows has one of them selected here and the choice is unmarked too (see `grid_tariff` in the response). Those rows are normally different tariff structures rather than competing prices, and the one selected is the structure most households in that market are on, so their per-kWh values are not comparable: each Flemish operator files a digital-meter and an analogue-meter row, and the digital row's `grid` is lower because that regime is billed partly on a capacity tariff per kW of metered peak while the analogue one carries a flat annual charge instead — neither of which any v1 or v2 response carries, and which bring the two within a few percent of each other over a year. Do not read a per-kWh gap between an operator's rows as a price difference; name the row your customer's meter is on and add the non-kWh legs from the sheet the tariff's `link` points at. It also selects the address's time-of-use switching times, operator- or location-specific fees with `include=fees` — an operator's 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 for this postal code — and an address-specific VAT rate with `include=vat`; without it only country-wide fees apply. It does not select the day-ahead bidding zone. Where a country clears in more than one — Norway (NO1-NO5), Sweden (SE1-SE4), Denmark (DK1/DK2) — a supplier sells one spot product per zone and files one tariff for each, so the zone is a property of the `consumption_tariff` id and never of the address. A tariff for a zone other than the one the postal code lies in is priced exactly as asked: a 200, the address's own `grid` and `fees` over that other zone's energy price, and nothing in the response naming either zone. The zones diverge by more than the whole retail energy component and differ in sign, so pick the id for the zone your customer is in. Great Britain has the same shape on the network axis: one bidding zone but fourteen distribution regions, with the trailing letter of a GB supplier tariff id naming the region, and — because GB suppliers quote one all-in price per region — that region's network charge already taken back out of the stored `energy`. A tariff for one region paired with a postal code in another is a 400 naming both regions and the row to send instead: served, it would put one region's carve-out over another region's `grid` and sum to a rate no supplier published. To price a region deliberately, omit `postal_code` and pass that region's `grid_tariff`. `GB` is Great Britain alone. A Northern Ireland postal code (`BT`) is accepted, resolves no operator, and is priced on a Great Britain supply product with no `grid` component: Northern Ireland is in the all-island Single Electricity Market, with its own regulator, network operator and suppliers, and no country code here covers it. From 1 October 2026 its VAT also differs, the temporary zero rate on domestic electricity covering Great Britain only while Northern Ireland stays at 5%. Belgium has the same shape on the regulatory axis: a 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, at ENGIE, one letter of the id (`ENGIF…`, `ENGIW…` and `ENGIB…`). A per-region product paired with a postal code in another region is a 400 naming both regions — ENGIE's, and every other supplier's that files one tariff per region: served, it priced a contract that cannot be signed at that address, on the wrong clock and, at some suppliers, the wrong energy price. The energy price may match — ENGIE publishes one national Empower price across all three regional cards — so a plausible price is not evidence the region is right; what differs is the time-of-use clock the region sets and the tariff carries, and a Walloon address priced on a Flemish product was billed the peak register straight through Wallonia's 11:00-17:00 off-peak window. A tariff filed without a region is priced at any Belgian address, and nothing in the response or the tariff listing names a product's region. Pick the product for your customer's region. The switching times move with the address only where the operator publishes a schedule and the tariff is priced against it: a tariff whose own prices are stored against clock times, as France's Heures Creuses rows are, switches at those times at every address. For France's Heures Pleines / Heures Creuses options those times are a reference window, off-peak from 23:00 to 07:00 Paris time, because the network operator assigns each meter its own eight off-peak hours, which only the customer's bill states and no parameter carries: for a meter on other hours, apply the served off-peak and peak prices to its own window. An empty value (`postal_code=`) is answered exactly as omitting the parameter is. A postal code that is not mapped returns 200 with no `grid` component, except where the grid price is set nationally and applies without a postal code — `grid_tariff` in the response names the tariff actually priced, so a response carrying it has a network charge in `grid` and one without it has none. Assert on that rather than on the country. In that exception the tariff named is the market's own default rather than one filed by an operator serving the address, because a nationally set price is the same wherever it is filed: an unmapped Italian CAP, and a string that is no Italian postal code at all, are both priced on e-distribuzione's copy of ARERA's national tariff. Use `GET /{country}/{sector}/companies?postal_code=` to tell a mapped address from an unmapped one — it answers with the serving operator or with an empty list. Great Britain is the sharpest case of the coarser-map rule above: an outward code is coarser than the distribution regions, and 270 of the 2,863 mapped codes hold addresses in two of them, so the region holding most of the code's addresses is the one selected and the response does not mark it. Northern Ireland (`BT`) resolves no operator at all, as above. Case, spaces, hyphens and a leading tag naming the path's own country are ignored; in NL only the four digits of a Dutch four-digits-and-two-letters code are used, in GB the outward code. The postal code is never checked against the path's country: a code tagged with another country (`DE-10115` on `/NL/`), or one of another country's shape, is not refused — it maps to no operator and is answered as any unmapped code is. Send each address under its own country. In FR a postal code in Corsica or an overseas department is a 400: VAT there differs from the mainland rate served here. That check needs the postal code — leave it out and any French address is priced on the mainland stack, one off the mainland included. France is the only market that refuses. Spain resolves its own territories instead: a postal code in the Canary Islands (`35`, `38`) is served the Canary IGIC, and one in Ceuta (`51`) or Melilla (`52`) the IPSI, in `vat` at the household rate (see `vat` in the response). Italy resolves its two the same way: 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. One other serves a territory smaller than the country on the country's mainland stack, and nothing in the response marks it: in PT the Azores and Madeira (`9xxx-xxx`) are priced on the mainland access tariff and the mainland IVA rate, though both autonomous regions run their own regulated network tariffs and their own lower rates. Germany resolves its two instead: 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 network levies and the municipal concession fee, which neither statute levies, stay; Büsingen am Hochrhein (`78266`), excluded by the same two sentences, takes its electricity from a Swiss operator, so it resolves no German operator and is refused. Confirm the territory before billing an address in any of them. NL is a third case and the only one no postal code can reach: `NL` prices the European Netherlands. 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 such an address cannot be named here even to be refused.","schema":{"maxLength":16,"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DayAheadV2DTO"}}}},"400":{"description":"Unknown `country`; no tariff id supplied; a tariff id that does not exist, or that names a company or a tariff of another sector (the message says which); a tariff that belongs to a different country than the path (the message names its country); a `version` that is not a YYYYMMDD date; a `historic_days` that is not a whole number from 0 to 3; a `resolution` other than 3600, 1800 or 900; an `include` value other than `fees` and `vat`; or a `postal_code` that names another country, lies in a territory served as a market of its own (Corsica and the French overseas departments, Northern Ireland on GB, the Azores and Madeira on PT), or resolves no grid operator in a market whose network price follows the operator (the message says which); or a `consumption_tariff` or `feedin_tariff` sold in a region the `postal_code` does not lie in — Great Britain, where the trailing letter of a supplier tariff id is its distribution region, and Belgium, where a supplier files one tariff per region the product is sold in. Also returned for a query parameter the route does not define.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":400,"message":"No tariff found for id ETID1"}}}},"401":{"description":"Missing `Authorization: Bearer <token>` header, a malformed header, or a token that is unknown or revoked. The `WWW-Authenticate` response header says which: `Bearer realm=\"tounify\"` alone when no credential was sent, `error=\"invalid_request\"` for a malformed header, `error=\"invalid_token\"` for a token that is not accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":401,"message":"Unknown or revoked token"}}}},"403":{"description":"The token is recognised but not entitled to this request: the subscription is not active; the testing token has expired (regenerate it on the Cockpit Token page); or the testing token has reached its total of different companies or tariffs — the body then carries `testingLimit`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicForbiddenErrorDTO"},"example":{"statusCode":403,"message":"Token is not entitled to this request"}}}},"429":{"description":"Testing tokens only: another request from the same token is still running (send them one after another), or a daily limit is reached. Only the daily limit on new things asked about on this endpoint carries the `rateLimit` block. The limits are listed under *Rate limits* in the introduction.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRateLimitErrorDTO"},"example":{"statusCode":429,"message":"Request limit exceeded","error":"Too Many Requests","rateLimit":{"limit":5,"remaining":0,"resetAt":"2026-08-07T00:00:00.000Z"}}}}},"500":{"description":"The price series could not be produced: no price at all is published yet for the requested tariff and period (a period published only in part is a 200 whose series ends at the last published point), the tariff prices by time-of-use bands whose switching times are not available for this location, or the tariffs cannot be combined into one series. The identical request returns the same result until the missing prices are published; quote the `X-Request-Id` response header when you contact support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorDTO"},"example":{"statusCode":500,"message":"No new prices available for ETID1"}}}}},"security":[{"bearer":[]}],"summary":"Get day-ahead prices","tags":["v2"]}}},"info":{"title":"tounify.io API","description":"__tounify__ returns European electricity tariffs and their per-kWh price series — energy, grid, regulatory fees and VAT as separate components.\n\n## Authentication\n\nEvery `/v2` endpoint takes an `Authorization: Bearer <token>` header. The *bearer* security\nscheme in this reference says how to get a testing token.\n\n## Quickstart\n\nHourly prices of aWATTar's HOURLY tariff (`HLAT`) for an address in Vienna:\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_KEY\" \\\n  \"https://api.tounify.io/v2/AT/dayahead?consumption_tariff=HLAT&postal_code=1010&include=fees,vat\"\n```\n\nThe postal code selects the grid operator, whose charge arrives as `grid`; `include=fees,vat` adds\nthe regulatory fees and VAT. Each price point carries `energy`, `grid`, `fees` and `vat`\nseparately, per kWh — what the customer pays per kWh is their sum.\n\n## Endpoints\n\n`{country}` is an ISO 3166-1 alpha-2 code (`DE`, `GB`) and `{sector}` is one of\n`consumption`, `feedin`, `grid`. A tariff belongs to a company, so listing tariffs needs the\ncompany id first.\n\nCompanies and tariffs are separate namespaces, and the same string can occur in both (`ENED` is a\nDutch supplier and also another Dutch supplier's tariff). Store an id together with its country, its\nsector and whether it names a company or a tariff. Ids are case-sensitive — send one exactly as a\nlisting returned it (`vatn` is not `VATN`). The country is the path's: a listing only ever\nreturns the companies and tariffs of the country in its path, which is why its items do not repeat\nit.\n\n| Route | Returns |\n|---|---|\n| `GET /v2/{country}/{sector}/companies` | Companies with a tariff in this sector |\n| `GET /v2/{country}/{sector}/{company}/tariffs` | A company's tariffs — the household catalogue |\n| `GET /v2/{country}/{sector}/{tariff}/versions` | The dates a tariff's configuration changed, newest first — price one with `version` on `/dayahead` |\n| `GET /v2/{country}/dayahead` | Price series for a consumption, feed-in and/or grid tariff, optionally with fees and VAT |\n| `GET /public/country-stats` | No token required — what is held per country, counted per sector; an entry counted 0 is not a catalogue |\n| `GET /public/attribution` | No token required — the data sources to credit, and how |\n\nThe listings are the household catalogue: grid tariffs for commercial or demand-metered connections,\nand supplier products published for business customers only, are not listed, and no `/v2` route\nreturns their ids. An id your integration already stores keeps pricing on `/dayahead`.\n\nFull parameters and response shapes for each `/v2` route are in the reference below.\n`GET /public/country-stats` is not: it returns an object keyed by country code, each entry with\n`companies` and `tariffs` (counts per sector), `hasTariffs` (the one answer to \"is this market\ncovered\": at least one tariff in any sector), `postalCodes`, `hasFees`, `feeCoverageComplete` and\n`hasLocationScopedFees`. Both count what is held rather than what the\nlistings show: a tariff the household catalogue leaves out is counted, and so is a company whose\nevery tariff it leaves out — so `companies.consumption` can exceed the length of\n`GET /v2/{country}/consumption/companies`, and does wherever a market has suppliers selling to\nbusiness customers only. That difference is also how to tell withheld from not held: where a\nsector's count equals what that market's listings return, nothing is withheld behind them and there\nis no commercial or demand-metered id to pass, whether or not you already store one. In the\nNetherlands `tariffs.grid` is exactly the connection bands the grid listings return, all of them\nsmall-user bands. `companies.total` counts suppliers, not companies: the distinct companies\nwith a consumption or a feed-in tariff, never a network operator, which are a separate register and\nare counted in `companies.grid` alone. `feeCoverageComplete` says this market's statutory\nper-kWh levies are settled — either rows are held, or the market provably levies none on a\nhousehold, which is why it can be `true` beside `hasFees: false`. It is a statement about the\nmarket, not about your customer: it does not promise that every levy is priced for the volume, the\ncustomer class or the address you are pricing, and the stated limits on `fees` still apply.\n`hasLocationScopedFees` says\nat least one of those rows is scoped to an address, so a price asked in that market without\n`postal_code` is short a fee or carries the country VAT rate where the address does not.\n\nA country is in this response once anything is held for it, which is not the same as holding a\ncatalogue: an entry counted `0` in every sector is a market whose fee answer is settled and whose\nsupplier and operator catalogues are not built yet. A country absent from it holds nothing at all.\n\nThere is no currency in this response because it does not vary within a market: every price is in\nthe market's own national currency, which each `/dayahead` response names in `currency` as an\nISO 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).\n\n## Data sources and attribution\n\nPart of the data comes from public sources whose licences ask for a credit — CC BY 4.0, the\nNorwegian NLOD, the Datenlizenz Deutschland and others. `GET /public/attribution` lists each\nsource with its publisher, licence and the exact `notice` to show; `?country=DE` narrows it to\none market. Every response carries a `Link` header pointing at it with `rel=\"license\"`.\n\nWhere you display or pass on data from this API, show the notices of the sources for that market,\nor link to that resource. Keep the `updated` date next to a source that has one, and note that\n`shareAlike` sources pass their licence on to a dataset you build from them and share.\n\n## Errors\n\nAn unknown company or tariff id is a `400`, never a `404`; a `404` means the path does not\nexist. So is an id from another country than the path, and one in the wrong sector or slot — a\nconsumption tariff passed as `feedin_tariff`, a supplier on a `grid` route: the message names the\ncountry the id belongs to, or what the id names instead: a company, a tariff of another sector, or\nthe id it differs from only in case. A postal code is not checked the same way;\nsee `postal_code` on `/dayahead`. A malformed value is a `400` too: an `available` other than true or false, a `type` other\nthan dynamic or static, an `include` value other than fees and vat, a `version` that is not a\nYYYYMMDD date, a `historic_days` that is not a whole number from 0 to 3, a `resolution` other than\n3600, 1800 or 900. On `/dayahead` so is a query parameter the route does not define; the listing\nroutes ignore one.\n\nA narrower price still returns `200`. Leaving out `postal_code` or `include=fees` shows only as\nabsent keys (`grid_tariff`, `grid`, `fees`). Decide per market what a complete price needs, and\nassert on those keys in your tests rather than eyeballing the number.\n\nThe converse does not hold, so do not assert that a bad address leaves `grid` out. Where the market\nprices the network nationally the charge is added whatever the address says, and a postal code that\nbelongs to no operator — or to no country — is accepted in silence. Establish which kind of market it\nis once: call `/dayahead` with neither `grid_tariff` nor `postal_code`, and a `grid_tariff` in\nthe response means the network price there is national.\n\n`401` — missing `Authorization: Bearer <token>` header, a malformed header, or a token that is\nunknown or revoked. The `WWW-Authenticate` response header tells these apart with RFC 6750's error\ncodes: `Bearer realm=\"tounify\"` alone when no credential was sent, `error=\"invalid_request\"` when\nthe header is not `Bearer <token>`, and `error=\"invalid_token\"` when the token is not accepted.\nBranch on that header, not on `message`.\n\n`403` — the token is recognised but not entitled to this request: the subscription is not active,\nthe testing token has expired, or it has used up its total allowance (see below).\n\n`429` — testing tokens only; see below.\n\n`500` — `/dayahead` only: the price series could not be produced. Quote the `X-Request-Id`\nresponse header when you contact support.\n\n## Rate limits\n\nOnly testing tokens are limited; a production token on an active subscription is not. Which one you\nhold is in the token itself: a testing token's value begins `tounify_test_sk_`, a production\ntoken's `tounify_prod_sk_`. Everything in this section, the headers at the end included, applies to\nthe first and to nothing else.\n\nThere is no separate test environment: a testing token calls this same API at the same base URL and\nis served the same data a production token is, so what you validate while evaluating is what you are\nserved once you pay. It differs in how much it may ask, and in one thing besides: the deprecated\n`/v1` endpoints refuse it with a `403`. A testing token:\n\n- is valid for **7 days**; renew it on the Cockpit Token page. Past that, a `403`.\n- makes **one request at a time**. A request sent while another from the same token is still\n  running is refused with a `429`; send them one after another.\n- asks about at most **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\n  something already asked that day is free, whatever else you change. Past it, a `429` whose\n  `rateLimit` block carries `resetAt`.\n- makes at most **100 requests per day** per account across all endpoints, and at most **300 per\n  day** from one client IP address. Past either, a `429` without a `rateLimit` block.\n- queries at most **20 different companies** (suppliers and network operators) **and 20 different\n  tariffs** per account in total. Past that, a `403` whose `testingLimit` block names what ran\n  out and which ids were refused; ids you have queried before stay available. This allowance never\n  resets, and regenerating the token does not reset it.\n\nDaily limits reset at midnight UTC. Testing-token responses carry `X-RateLimit-Limit`,\n`X-RateLimit-Remaining` and `X-RateLimit-Reset` for the daily allowance of new things, and\n`X-Testing-Companies-Remaining` and `X-Testing-Tariffs-Remaining` for the totals. The allowances\nare set per account: write to [connect@tounify.io](mailto:connect@tounify.io) to have them raised.\n\n## Versioning\n\n`/v2` is current. `/v1` is deprecated, still served for existing integrations, and should not be\nused for new work.","version":"2.0.0","contact":{"name":"tounify","url":"https://tounify.io","email":"connect@tounify.io"},"termsOfService":"https://tounify.io/terms-and-conditions"},"tags":[{"name":"v2","description":"Current, stable version of the tounify API. Use these endpoints for new integrations."}],"servers":[{"url":"https://api.tounify.io"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"API token for your organisation. Register at https://cockpit.tounify.io/register to be issued a testing token immediately — no credit card and no sales call — then copy it from the Token page. Send it as `Authorization: Bearer <token>`. It is an opaque string, not a JWT despite the `bearerFormat` hint on this scheme: nothing in it is readable, neither claims nor an expiry, so store it as a credential rather than parsing it, and read a testing token's expiry from the Cockpit Token page. A production token stays valid until you revoke it on that page; from the next request it answers `401`. An account may hold more than one production token at a time, so rotate one by creating its successor, deploying it, then revoking the old one. The testing token cannot be revoked: regenerating it replaces its value, and the old value answers `401` at once."}},"schemas":{"CompanyDTO":{"type":"object","properties":{"id":{"type":"string","description":"Unique ID of the company","example":"CID1"},"name":{"type":"string","description":"Public name of the company","example":"Energy Supplier A"},"country":{"type":"string","description":"Two digit country code (ISO 3166-1 alpha-2)","example":"AT"},"url":{"type":"string","description":"Link to the company website","example":"https://www.energy-supplier.com"}},"required":["id","name","country"]},"PublicErrorDTO":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code, repeated in the body","example":400},"message":{"type":"string","description":"Human-readable cause — a string, or an array of strings when the query or the request body fails validation. Not a stable identifier — do not branch on its text.","example":"No tariff found for id ETID1"}},"required":["statusCode","message"]},"PublicTestingLimitDTO":{"type":"object","properties":{"kind":{"type":"string","description":"Which allowance ran out: 'companies' or 'tariffs'.","example":"tariffs"},"limit":{"type":"number","description":"How many different ones this account may query in total","example":20},"used":{"type":"number","description":"How many have been queried so far","example":20},"remaining":{"type":"number","description":"How many are still available","example":0},"blocked":{"description":"The ids in this request beyond the allowance. Ids you have already queried stay available.","example":["ETID42"],"type":"array","items":{"type":"string"}}},"required":["kind","limit","used","remaining","blocked"]},"PublicForbiddenErrorDTO":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code, repeated in the body","example":403},"message":{"type":"string","description":"Human-readable cause. Not a stable identifier — do not branch on its text.","example":"This testing token has already queried its maximum of 20 different tariffs. The ones you have queried before stay available. Contact connect@tounify.io to have the limit raised."},"error":{"type":"string","description":"Status text","example":"Forbidden"},"testingLimit":{"description":"Present only when a testing token was refused for having exhausted its allowance of different companies or tariffs. Names which allowance ran out and which ids were refused. Absent on every other 403 — a token without an active subscription, for example.","allOf":[{"$ref":"#/components/schemas/PublicTestingLimitDTO"}]}},"required":["statusCode","message"]},"PublicTariffDTO":{"type":"object","properties":{"id":{"type":"string","maxLength":32,"description":"Unique ID of the tariff","example":"ETID1"},"companyid":{"type":"string","description":"Unique ID of the company that offers the tariff","example":"CID1"},"name":{"type":"string","description":"Public name of the tariff","example":"Tariff Name 1"},"link":{"type":"string","nullable":true,"description":"Link to the tariff information page","example":"https://www.energy-utility.com/tariff-name1"},"description":{"type":"string","nullable":true,"description":"Short description of the tariff, carried through from the supplier or catalogue that publishes one. Most sources publish none, so this is null far more often than not — 228 of the 229 Finnish consumption tariffs, for instance — and it is not a field to read a product's shape from. Where it is present it is usually the source's own wording and may describe a shape the price model does not carry: `NGEFS` reads \"50% fix, 50% market price\" and is priced as the market leg alone, because the fixed half is a per-contract price no catalogue publishes. A minority of rows carry this catalogue's own note instead, where the source's sheet attaches an eligibility no other field can show. German grid rows for the pre-2024 § 14a EnWG regime are the case: the device-class charges for storage heating, heat pumps and e-mobility, and the generic *steuerbare Verbrauchseinrichtung* row, say here that they are closed to a device commissioned from 1 January 2024 — which `available` does not say, because the operator still publishes the price for the customers already on it.","example":null},"type":{"nullable":true,"enum":["static","dynamic"],"type":"string","description":"'dynamic': the price is read from a published series and is not known until that series is published — a spot market, or a calendar whose value for a given day is published day by day. 'static': a fixed price per period, known in advance from the tariff itself, including a rate computed from a market average and a time-of-use tariff whose rate changes during the day on a fixed repeating clock. 'static' therefore does not mean one rate all day: for the rate of a given hour, read the per-interval prices either way. null when the tariff is not classified. A supplier's own ceiling or floor on a spot-linked price does not change the type: such a tariff is still 'dynamic', and the served prices already have the bound applied — AT `HAAGSHA` caps the exchange price at 0.15 EUR/kWh and serves 0.17 with its 0.02 handling fee on top, DE `VATDKDL` caps it at 0.25. Nothing in the response names the bound, so a caller reconstructing the series from a raw exchange feed will not reproduce it. A lock the customer opts into for a month or a quarter at a time (FI `VIAE-586FE4BB`, *Hintalukko*) is not a property of the tariff at all: the catalogue cannot know whether a given customer has taken one, and prices the product as the spot contract it is between locks.","example":"dynamic"},"available":{"type":"boolean","description":"Whether the source still publishes this tariff — the supplier's price list, or the network operator's price sheet for a grid tariff. Not a statement about who may take it: a tariff still published can be closed to new customers, and the eligibility its own sheet attaches to the row — a commissioning date, an individual agreement, which of several network-charge regimes the customer is on — is not carried here.","example":true}},"required":["id","companyid","name","link","description","type","available"]},"PublicRateLimitDTO":{"type":"object","properties":{"limit":{"type":"number","description":"How many different things you may ask about per day on this endpoint","example":5},"remaining":{"type":"number","description":"How many more you may ask about before the window resets","example":0},"resetAt":{"type":"string","description":"ISO timestamp at which the window resets","example":"2026-08-07T00:00:00.000Z"}},"required":["limit","remaining","resetAt"]},"PublicRateLimitErrorDTO":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code, repeated in the body","example":429},"message":{"type":"string","description":"Human-readable cause. Not a stable identifier — do not branch on its text.","example":"Daily testing limit reached: 5 different energy companies per day on this endpoint. The ones you have already asked about today can still be queried as often as you like."},"error":{"type":"string","description":"Status text","example":"Too Many Requests"},"rateLimit":{"description":"The daily allowance of new things to ask about on this endpoint: what is left and when it resets. Only on the 429 for that allowance, and absent on the other 429s (another request still running, the daily request limits). Read `resetAt` rather than retrying on a fixed interval — the window is a calendar day in UTC.","allOf":[{"$ref":"#/components/schemas/PublicRateLimitDTO"}]}},"required":["statusCode","message","error","rateLimit"]},"TariffVersionsDTO":{"type":"object","properties":{"version":{"type":"string","description":"Date string in the YYYYMMDD format","example":"20230228"},"available":{"type":"boolean","description":"Whether the supplier still offered this version when it was last checked. The newest version's flag is the tariff's `available` in the listing; an older version's flag is not a statement about today.","example":true}},"required":["version","available"]},"ShortTariffInfoDTO":{"type":"object","properties":{"id":{"type":"string","description":"ID of the tariff used","example":"TID1"},"type":{"nullable":true,"enum":["static","dynamic"],"type":"string","description":"'dynamic': the price is read from a published series and is not known until that series is published — a spot market, or a calendar whose value for a given day is published day by day. 'static': a fixed price per period, known in advance from the tariff itself, including a rate computed from a market average and a time-of-use tariff whose rate changes during the day on a fixed repeating clock. 'static' therefore does not mean one rate all day: for the rate of a given hour, read the per-interval prices either way. null when the tariff is not classified. A supplier's own ceiling or floor on a spot-linked price does not change the type: such a tariff is still 'dynamic', and the served prices already have the bound applied — AT `HAAGSHA` caps the exchange price at 0.15 EUR/kWh and serves 0.17 with its 0.02 handling fee on top, DE `VATDKDL` caps it at 0.25. Nothing in the response names the bound, so a caller reconstructing the series from a raw exchange feed will not reproduce it. A lock the customer opts into for a month or a quarter at a time (FI `VIAE-586FE4BB`, *Hintalukko*) is not a property of the tariff at all: the catalogue cannot know whether a given customer has taken one, and prices the product as the spot contract it is between locks.","example":"dynamic"},"available":{"type":"boolean","description":"Whether the source still publishes this tariff — the supplier's price list, or the network operator's price sheet for a grid tariff. Not a statement about who may take it: a tariff still published can be closed to new customers, and the eligibility its own sheet attaches to the row — a commissioning date, an individual agreement, which of several network-charge regimes the customer is on — is not carried here.","example":true}},"required":["type","available"]},"DayAheadV2PricePointDTO":{"type":"object","properties":{"from_utc":{"type":"number","description":"Start time of the price value as UNIX timestamp","example":1605636000},"energy":{"type":"number","description":"Energy price per kWh, net of the network charge, of levies and of VAT. Where a supplier publishes one bundled price — every tariff in Great Britain, and France's regulated Tarif Bleu — the published figure is the **sum** of the components, and this one is what is left of it after `grid` and `fees`. It can therefore move hour to hour on a tariff the supplier publishes as a single flat rate, because the network share of a flat price does. Reconcile a bundled market against the sum, never against this component on its own. On a tariff priced off an exchange this is the supplier's selling price for the hour, not the exchange's: the product's own price formula applied to the day-ahead price, with nothing in the response separating the two. Where the formula only adds a per-kWh margin — the shape of the spot-linked products held in Germany, Finland and the Netherlands, and of most in Austria — reconciling against a 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 and is no single margin: an Italian variable offer applies the network-loss uplift to the index as well as to the supplier's spread, and several Belgian products bill a stated coefficient times Belpex plus a constant. Reconcile those against the supplier's own formula, never against a constant. A tariff indexed to a monthly average published after the month ends — Italy's PUN-indexed offers — is priced on the latest month for which the index is held, carried forward over every later hour until a newer month is published, so every hour carries the same figure and the response does not say which month it is. Absent, never 0, when no supply tariff is priced because only a grid tariff is given. The points are then the network and levy legs alone, `vat` is the tax on those alone, and their sum is not a per-kWh retail price.","example":0.0924},"grid":{"type":"number","description":"Grid price per kWh. 0 where the network charge has no per-kWh part — for every Dutch connection band served here the whole network charge is an annual amount per connection, which is not in this response. That is the band's property, not the country's: above the Dutch small-user boundary of 3x80 A the network charge does carry a per-kWh transport rate, and no tariff above that boundary is held, so a 0 here never states that a commercial connection has no per-kWh network cost. A statutory per-kWh levy that the operator collects inside its own published network rate is inside this figure and is not repeated in `fees` — Norway's Energifondet levy is the case: it sits here while the electricity duty sits in `fees`. Reconcile a network invoice against `grid + fees` together, never against either alone. Where a market sells all-in and its network charge reaches this response through the regulator's retail price control rather than an operator's own published network rate, this figure is that control's network allowance for the address's region, set for household supply and expressed per kWh against the regulator's typical household consumption. Great Britain is that market: the split of a British price into `energy`, `grid` and `fees` is nominal — only their sum is a figure a supplier published, a competitively priced product carries its own network and policy costs rather than the allowance, and a non-household site's own network charge is neither. `grid_tariff` names the row priced; its `name` and `link`, which say what the figure is, are on `GET /{country}/grid/{company}/tariffs` and not in this response.","example":0.0871},"fees":{"type":"number","description":"Regulatory levies and surcharges per kWh, net of VAT. Can depend on the operator or location selected by `postal_code`. A levy or credit charged per connection or per year is not included. A levy banded by annual consumption is resolved on the annual consumption the request itself carries, and comes at the ladder's first rung where it carries none. Asking for `fee_components` carries the ladder beside the rate it resolved to, so a rung that was defaulted is visible rather than silent. The Dutch energy tax is held as a single rate rather than as a ladder, so it comes at the rate charged on the first 10,000 kWh a year however much is consumed, and consumption above that is taxed at lower statutory rates you apply yourself. Priced for household supply unless the request states another customer class: a levy set per customer class comes at the rate held for that class, and where none is held for it the levy is absent rather than re-rated, so the figure is lower by it and nothing marks the omission. In Germany the municipal concession fee is the rate of the operator `postal_code` resolves where it is held, otherwise the lowest of the statutory household caps, so the figure is never above what a municipality may charge and is low wherever the address's own rate is higher — and it is held at that household rate alone, so a supply priced as commercial is served none of it. A levy the network operator collects inside its own published network rate is carried in `grid` instead of here, because that rate is what the operator bills and splitting it would double-count: Norway's Energifondet levy is inside `grid` while its electricity duty is here. So a per-layer reconciliation against a network invoice is done on `grid + fees` together. Italy is the exception the other way: its perequative components UC3 and UC6 are here, although ARERA bills them inside the network charge («Tariffa per l'uso della rete»), so an Italian `grid` is the transport-and-distribution quota σ3 alone and ARERA's network line is `grid` plus those two. In an all-in market the levy side comes from the same retail price control as `grid`: Great Britain's figure is the price cap's per-kWh policy allowances — the renewables obligation, the legacy feed-in tariff, the per-kWh part of the warm home discount, the assistance for areas with high distribution costs, the energy-intensive-industry network charging compensation and the nuclear RAB charge — and the Climate Change Levy is not among them, because it is charged on non-household supply only. That is the household-supply rule above in its sharpest form: the levy exists and no request here can ask for it, so a business caller adds it themselves.","example":0.0154},"vat":{"type":"number","description":"VAT per kWh on the sum of the other components in this response. Without `include=fees` that sum has no levies, so this component then leaves out the VAT owed on them too — in the Netherlands, the VAT on the energy tax — and nothing else marks it: ask for `include=fees,vat` for the tax a customer pays. The rate is the one that country charges on household electricity supply — which is the catalogue these listings serve, and which in several markets is a reduced rate rather than the standard one — or the address-specific rate where `postal_code` resolves one; it is never derived from the consumption volume or the customer class. So where a market taxes non-household supply at a different rate, this component is not that rate and no request can ask for it: recompute it yourself over the sum of the other three, which are net of VAT. A VAT territory smaller than the country is carried only where a rate is held for it. Spain is the market where it is: an address in the Canary Islands (`35`, `38`) is served the Canary IGIC and one in Ceuta (`51`) or Melilla (`52`) the IPSI, in this same component under the same name, and at the household rate — IGIC 0 % applies only to a dwelling contracted at up to 10 kW, and any other Canary supply owes 3 % that this component does not carry. Italy holds one too: Livigno (`23041`) and Campione d'Italia (`22061`) are outside the EU VAT territory and no local tax replaces it on a supply delivered over a network, so this component 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 holds one as well: Helgoland (`27498`) is named in the sentence that defines each of the two German tax territories (UStG § 1 (2), StromStG § 1), so this component is 0 there and `fees` carries no electricity duty either, while the network levies and the municipal concession fee, which neither statute levies, stay. Where none is held, the postal code is either refused outright — France's Corsica and overseas departments, and Büsingen am Hochrhein (`78266`), excluded by the same two German sentences but supplied from Switzerland and so resolving no German operator — or priced at the country rate, today Portugal's Azores and Madeira. `GB` has one too: a Northern Ireland postal code (`BT`) is served the Great Britain rate, which from 1 October 2026 is the temporary 0 % on domestic electricity while Northern Ireland stays at 5 %. Confirm the territory before billing an address outside the mainland.","example":0.03898}},"required":["from_utc"]},"DayAheadV2DTO":{"type":"object","properties":{"consumption_tariff":{"description":"Present if a consumption tariff was selected","allOf":[{"$ref":"#/components/schemas/ShortTariffInfoDTO"}]},"feedin_tariff":{"description":"Present if a feed-in tariff was selected","allOf":[{"$ref":"#/components/schemas/ShortTariffInfoDTO"}]},"grid_tariff":{"description":"The grid tariff priced: the one passed as `grid_tariff`, or the one selected from `postal_code` or the national grid tariff. Where an operator files several household tariffs, `postal_code` selects one of them and nothing here marks that a choice was made, because the axis they differ on is in no request: the connection's capacity band in the Netherlands, and in Flanders the metering regime, where an operator's classic-meter and digital-meter tariffs are separate rows priced differently at the same address. Sweden has the same shape, and its rows are the regulator's type-customer filings rather than the operator's own price list: Energimarknadsinspektionen publishes each operator's household tariff for six standard customers. `postal_code` selects the *Villa 16A, 5 000 kWh/år* row, or the *Lägenhet 16A, 2 000 kWh/år* one 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, named for their standard customer from *Villa 20A, 10 000 kWh/år* to *Villa 25A, 30 000 kWh/år*: `postal_code` never selects one, and `grid_tariff` names it. Most operators file the same per-kWh rate at every fuse, but some do not, and at Bodens Energi Nät, Luleå Energi Elnät and PiteEnergi Elnät the larger-fuse rows carry no per-kWh charge at all, the whole network charge there being the annual fixed one this response does not carry. A time-of-use network product, Vattenfall's *tidstariff* among them, has no row of its own: 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 and nothing marks it, and an operator that files only such a blend for a standard customer has no row for that customer. Where a Swedish row was read from the operator's own price sheet instead, it carries what that sheet publishes, clock included — Nacka Energi and Skövde Energi Elnät are priced on a låglast/höglast rate that switches on weekdays 06:00–22:00 from November to March. `GET /{country}/grid/{company}/tariffs` lists the operator's rows; pass `grid_tariff` to price one of the others. Its prices are the `grid` component of the consumption series, so without a consumption series it is priced nowhere. Absent when no grid tariff applies, including a `grid_tariff` passed in a country without grid tariffs.","allOf":[{"$ref":"#/components/schemas/ShortTariffInfoDTO"}]},"currency":{"enum":["","EUR","CHF","DKK","SEK","CZK","HUF","NOK","PLN","RON","GBP","AUD"],"type":"string","description":"Currency of the price value in ISO 4217 format. The price is always per kWh.","example":"EUR"},"country":{"type":"string","description":"Two digit country code (ISO 3166-1 alpha-2)","example":"AT"},"resolution":{"type":"number","description":"Seconds between the pricing values","example":3600},"next":{"type":"number","description":"Recommended time to request new pricing information (UNIX timestamp). It is the moment this tariff's price source next publishes, or the ingest of that publication where that is later, plus a random offset of up to 30 minutes drawn afresh on every request — so two identical requests return values up to half an hour apart, and the value is advice rather than a fact about the data. Schedule from it rather than on a fixed interval; poll from 30 minutes before it if you need tomorrow the moment it exists. When a publication is late — due, and not yet in the series — it is instead a retry a few minutes out, repeated until the publication lands, rather than the following day's publication. Until the source has published, the series returns 200 and simply ends at the last published point, with no field marking it short. A tariff with no price feed (a static price) publishes on no schedule: its `next` is 07:00 in the market's local time every day, a check-in rather than a publication, and its prices change only when a new version takes effect, which the versions endpoint lists.","example":1605701864},"consumption":{"description":"Present if a consumption tariff was supplied, or a grid tariff without a feed-in tariff. Sum the components for the total per-kWh price.","type":"array","items":{"$ref":"#/components/schemas/DayAheadV2PricePointDTO"}},"feedin":{"description":"Present if a feed-in tariff was supplied. Sum the components for the total per-kWh price.","type":"array","items":{"$ref":"#/components/schemas/DayAheadV2PricePointDTO"}}},"required":["currency","country","resolution","next"]}}}}