Dokumentace API
Spotovky.cz poskytuje spotové ceny elektřiny z OTE-CR přes REST API a MQTT broker. Vše je zdarma, bez registrace, bez API klíče.
Rychlý start
Nejrychlejší způsob jak získat data — stačí jedna HTTP žádost nebo MQTT subscribe.
REST API
curl https://api.spotovky.cz/v1/today
MQTT
mosquitto_sub -h spotovky.cz -t "v1/current/json"
Díky retain zprávám na MQTT dostanete data okamžitě po přihlášení — nemusíte čekat na další aktualizaci.
REST API
Base URL: https://api.spotovky.cz
Odpovědi jsou vždy ve formátu JSON s hlavičkou Content-Type: application/json.
Cache je řízena hlavičkou Cache-Control: public, max-age=N kde N je počet sekund do konce aktuální 15minutové periody.
Endpointy
Vrátí data pro dnešní datum (Europe/Prague)
Vrátí data pro zítřejší datum. Dostupné obvykle od 15:00 po publikaci z OTE-CR.
⚠ Pokud data pro zítřek nejsou k dispozici, vrátí dnešní data.
Vrátí data pro včerejší datum.
Vrátí data pro konkrétní datum ve formátu YYYY-MM-DD, např. /v1/2026-03-13.
• Datum v budoucnu (dále než zítřek) → vrátí zítřejší data
• Neplatný formát data → HTTP 400
• Data pro datum nejsou dostupná → vrátí dnešní data
Historická data jsou dostupná od spuštění služby. Starší záznamy mohou chybět.
Formát odpovědi
Každá odpověď obsahuje datum, kurz EUR/CZK a pole slots s 15minutovými intervaly.
{
"date": "2026-03-13", // datum (Europe/Prague)
"rate": 24.43, // kurz EUR/CZK z ČNB
"slots": [
{
"t": "00:00", // začátek intervalu
"czk": 2.60, // cena v Kč/kWh (zaokrouhleno na 2 des. místa)
"rank": 55 // pořadí od nejlevnější (1 = nejlevnější)
},
{
"t": "00:15",
"czk": 2.31,
"rank": 52
},
// ... celkem 92, 96 nebo 100 slotů (viz sekce Letní/zimní čas)
]
}
| Pole | Typ | Popis |
|---|---|---|
| date | string | Datum ve formátu YYYY-MM-DD |
| rate | number | Kurz EUR/CZK z ČNB platný pro daný den |
| slots | array | Pole 15minutových intervalů, seřazené chronologicky |
| slots[].t | string | Začátek intervalu ve formátu HH:MM |
| slots[].czk | number | Spotová cena v Kč/kWh, zaokrouhlena na 2 desetinná místa. Může být záporná. |
| slots[].rank | integer | Pořadí intervalu v rámci dne od nejlevnějšího (1 = nejlevnější) |
Záporné ceny — při přebytku solární nebo větrné energie mohou být spotové ceny záporné. Pole czk může obsahovat zápornou hodnotu, počítejte s tím ve svém kódu.
HTTP status kódy
| Kód | Popis |
|---|---|
| 200 OK | Úspěch. Odpověď obsahuje data. |
| 400 Bad Request | Neplatný formát data v URL (např. /v1/abc). Odpověď: {"error": "Invalid date format..."} |
| 503 Service Unavailable | Data nejsou dostupná ani pro dnešek (výpadek fetcheru). Odpověď: {"error": "No data available"} |
MQTT
Broker je dostupný na adrese spotovky.cz, port 1883. Připojení nevyžaduje uživatelské jméno ani heslo.
# mosquitto_sub mosquitto_sub -h spotovky.cz -p 1883 -t "v1/today/json" # Python (paho-mqtt) import paho.mqtt.client as mqtt client = mqtt.Client() client.connect("spotovky.cz", 1883) client.subscribe("v1/current/json")
Topicy
| Topic | Formát | Popis |
|---|---|---|
| v1/today/json | JSON | Dnešní ceny — všechny sloty. Retain, QoS 1. |
| v1/today/bin | Binární | Dnešní ceny — kompaktní binární formát. Retain, QoS 1. |
| v1/tomorrow/json | JSON | Zítřejší ceny — dostupné od ~15:00. Retain, QoS 1. Po půlnoci smazáno. |
| v1/tomorrow/bin | Binární | Zítřejší ceny — binární formát. Retain, QoS 1. Po půlnoci smazáno. |
| v1/current/json | JSON | Aktuální 15minutový interval. Retain, QoS 1. Aktualizuje se každých 15 minut. |
| v1/current/bin | Binární | Aktuální interval — binární formát. Retain, QoS 1. |
Formát zpráv today/json a tomorrow/json je shodný s odpovědí REST API. Zpráva current/json obsahuje pouze aktuální interval:
{
"t": "14:15", // začátek intervalu
"czk": 1.82, // cena v Kč/kWh
"rank": 12 // pořadí v rámci dnešního dne
}
Pravidla přístupu
Publish je zakázán. Broker přijímá pouze subscribe. Pokus o publish na jakýkoliv topic bude tiše odmítnut — zpráva nebude doručena a připojení zůstane aktivní.
Povolené topicy. Subscribe je možný pouze na topicy uvedené v tabulce výše. Subscribe na jiný topic bude odmítnut.
Wildcard subscribe (#, +) není povolen. Vždy se přihlašujte na konkrétní topic.
Opakované pokusy o zakázané operace mohou vést k dočasnému zablokování IP adresy.
Harmonogram aktualizací
| Čas | Akce | Ovlivněné topicy |
|---|---|---|
| 00:00 | Publikace dnešních cen, smazání zítřejších retain zpráv | today/json, today/bin, tomorrow/json*, tomorrow/bin* |
| */15 * * * | Aktualizace aktuálního intervalu | current/json, current/bin |
| 14:55 | Stažení dat z OTE-CR a ČNB | — |
| 15:00 | Publikace dnešních a zítřejších cen | today/json, today/bin, tomorrow/json, tomorrow/bin |
* Smazání retain zprávy = publish prázdné zprávy na daný topic s retain=true, standardní MQTT mechanismus.
Datové formáty
JSON formát
Podrobný popis viz sekce Formát odpovědi REST API. Zprávy na MQTT topicech today/json a tomorrow/json mají identickou strukturu.
Binární formát
Kompaktní formát pro embedded zařízení. Všechny hodnoty jsou little-endian.
today/bin a tomorrow/bin
| Offset | Velikost | Typ | Obsah |
|---|---|---|---|
| 0 | 8 B | uint64 | Unix timestamp půlnoci daného dne (Europe/Prague) |
| 8 | 2 B | uint16 | Kurz EUR/CZK × 100 (např. 2443 = 24.43 Kč/EUR) |
| 10 | 1 B | uint8 | Počet period N (92, 96 nebo 100 — viz letní/zimní čas) |
| 11 | N × 2 B | N × uint16 | Ceny v haléřích (czk/kWh × 100), záporné ceny jsou oříznuty na 0 |
| 11 + N×2 | N × 1 B | N × uint8 | Pořadí intervalu (1 = nejlevnější, N = nejdražší) |
Celková délka: 11 + N×3 bytů (283 B pro 92 period / 299 B pro 96 / 311 B pro 100).
Index slotu odpovídá pořadí od půlnoci: slot 0 = 00:00, slot 1 = 00:15, atd. Čas slotu: midnight_unix + index × 900.
current/bin
| Offset | Velikost | Typ | Obsah |
|---|---|---|---|
| 0 | 8 B | uint64 | Unix timestamp začátku aktuálního intervalu (UTC) |
| 8 | 2 B | uint16 | Cena v haléřích (czk/kWh × 100), min. 0 |
| 10 | 1 B | uint8 | Pořadí intervalu v rámci dne (1 = nejlevnější) |
| 11 | 2 B | uint16 | Kurz EUR/CZK × 100 |
Celková délka: vždy 13 bytů.
// current/bin — 13 bytů uint64_t timestamp; uint16_t halere, rate_x100; uint8_t rank; memcpy(×tamp, data + 0, 8); memcpy(&halere, data + 8, 2); rank = data[10]; memcpy(&rate_x100, data + 11, 2); float czk = halere / 100.0f; float eur_czk = rate_x100 / 100.0f; Serial.printf("%.2f Kč/kWh, rank %d, kurz %.2f\n", czk, rank, eur_czk);
import struct, datetime, zoneinfo def decode_day_bin(data: bytes): midnight, rate_x100, n = struct.unpack_from("<QHB", data, 0) prices = struct.unpack_from(f"<{n}H", data, 11) ranks = struct.unpack_from(f"<{n}B", data, 11 + n * 2) eur_czk = rate_x100 / 100 tz = zoneinfo.ZoneInfo("Europe/Prague") for i, (halere, rank) in enumerate(zip(prices, ranks)): slot_ts = midnight + i * 900 dt = datetime.datetime.fromtimestamp(slot_ts, tz) czk = halere / 100 print(f"{dt:%H:%M} {czk:.2f} Kč/kWh rank {rank}/{n}")
Letní a zimní čas (DST)
Počet slotů za den není vždy 96. OTE-CR publikuje skutečný počet 15minutových intervalů:
| Situace | Počet slotů | Velikost today/bin |
|---|---|---|
| Přechod na letní čas (poslední neděle v březnu) | 92 | 287 B |
| Běžný den | 96 | 299 B |
| Přechod na zimní čas (poslední neděle v říjnu) | 100 | 311 B |
Pole slots v JSON vždy obsahuje správný počet záznamů. V binárním formátu je počet period uložen v bytu na offsetu 10 — vždy čtěte tento byte před parsováním dat.
Nepředpokládejte pevný počet 96 slotů. Vždy použijte hodnotu N z binárního payloadu nebo délku pole slots z JSON.
Limity a podmínky
Dostupnost
Služba je provozována jako hobby projekt bez záruky dostupnosti. Nejsou poskytovány žádné SLA. Data mohou chybět v případě nedostupnosti OTE-CR API nebo výpadku serveru.
Zdroje dat
Spotové ceny pocházejí z OTE-CR (Operátor trhu s elektřinou). Kurz EUR/CZK pochází z ČNB (Česká národní banka) a je aktualizován jednou denně po 14:30. Pro víkendy a svátky se používá poslední dostupný kurz.
Ceny jsou pouze spotové — neobsahují distribuci, daně ani poplatky. Nejsou vhodné jako podklad pro fakturaci bez dalšího zpracování.
Použití
Data jsou veřejná a jejich použití není omezeno. Pokud službu využíváte ve svém projektu, oceníme zmínku o zdrojích dat (OTE-CR, spotovky.cz).
Kontakt
Dotazy, hlášení chyb nebo návrhy pište na martin@lysek.cz.