API
Відкрите JSON API: ті самі дані, що на карті. Без ключа та реєстрації.
Загальне
- База: той самий домен, шлях
/api/v1. JSON, UTF-8. - Час у форматі RFC 3339: у відповідях за Києвом, в історії в UTC.
- Читання віддається з незмінного знімка ревізії: сильний ETag і gzip,
Cache-Control: public, max-age=15..30. НадсилайтеIf-None-Match, щоб отримати 304. - Помилки:
{"error": "…", "code": "machine_code"}зі статусами 400, 403, 404, 422, 429, 503. - Ліміти: 600 читань на хвилину з IP (сплеск 150), 30 записів на хвилину. Записи потребують того самого походження (заголовок
Origin) і ставлять анонімний HttpOnly-cookiesp_dev.
Коди та стани
- oblast iso
- ISO 3166-2, наприклад
UA-46. Кожна область має йslug. - group
- Черга оператора, ключ
<operator_id>:<group>, наприкладlvivoblenergo:3.2. - group.state
on | off | maybe | unknown. «unknown» ніколи не слід малювати як «on».- group.class
planned | emergency | local | unknown | on- oblast.state
on | off | partial | emergency | unknown.off_share— частка черг без світла (0..1);stale— дані оператора старші за 45 хвилин.- restore_at
- ПЛАНОВИЙ час повернення (кінець поточного інтервалу вимкнення).
next_at / next_state— наступна планова зміна.
Час без даних повертається як unknown_min і не входить у on_share та avg_off_share.
Поточні дані
| Метод | Шлях | Що повертає |
|---|---|---|
| GET | /summary | Зведення: кількість черг і областей із відключеннями, свіжість операторів. Поле demo: true означає синтетичні дані. |
| GET | /oblasts | Усі 27 одиниць (24 області, Крим, Київ, Севастополь): стан, частка черг без світла, ознака «застаріло». |
| GET | /oblasts/{slug} | Одна область: оператори, черги, режими, 12 найбільших населених пунктів. |
| GET | /operators | Оператори: назви, кількість черг, скільки вимкнено, свіжість. |
| GET | /groups/{operator}/{group} | Черга: стан, клас, ймовірність, впевненість, покриття, плановий час повернення, графіки на сьогодні й завтра. |
| GET | /ics/{operator}/{group} | Планові відключення черги як iCalendar-стрічка (сьогодні, завтра та все, що вже відомо). Підпишіться в Google або Apple Calendar. Лише плани, без сигналів. |
| GET | /places?oblast=UA-46&limit= | 437 населених пунктів зі станом їхніх черг. |
| GET | /places/{slug} | Населений пункт: черги та найближчі пункти. |
| GET | /search?q= | Пошук населених пунктів та відомих адрес. Не кешується. |
| GET | /stream | SSE: подія snapshot із номером ревізії після кожного перерахунку (~30 с), коментар-«пульс» кожні 25 с. Після події перечитайте /summary та /oblasts. |
Історія
| Метод | Шлях | Що повертає |
|---|---|---|
| GET | /history/map?at= | Стани областей на момент T (RFC 3339 або unix), крок 5 хвилин, до 400 днів назад. |
| GET | /history/oblast/{iso}?from&to | Сегменти станів області та доступність (on/off/maybe/unknown, частки). Вікно до 31 дня, за замовчуванням остання доба. |
| GET | /history/group/{operator}/{group}?from&to | Те саме для однієї черги. |
| GET | /history/daily/{iso}?days=14 | Підсумки по кожній добі за Києвом (для календаря-теплокарти). |
| GET | /history/plan/{operator}/{group}?asof=&date= | Графік у тому вигляді, як його опублікував оператор на момент asof. |
Обговорення, звіти, підписки
| Метод | Шлях | Що повертає |
|---|---|---|
| GET | /posts?scope=&before=&limit= | Обговорення. scope: global, oblast:UA-46, place:<slug>, group:<оператор>:<черга>. |
| GET | /posts/{id}/replies | Відповіді на допис. |
| POST | /posts | Створити допис {scope, body, parent_id?}. 201 {id}. 422 з кодом restricted_topic, links_not_allowed, phone_not_allowed, coordinates_not_allowed, abuse, too_short, too_long, no_text. 429 після 5 дописів за 10 хвилин. |
| POST | /posts/{id}/like | Перемикач лайка. Відповідь {likes}. |
| POST | /posts/{id}/report | Скарга {reason}. Після 3 скарг допис приховується. |
| POST | /reports | Звіт {operator_id, group, state: "on"|"off"}. 202. Сигнал публічний лише після кворуму і затримки, а не окремо. |
| POST | /subscribe-link | Одноразове посилання на бота {operator_id, group, place_slug?, label?, address_text?, lead_minutes?[5..180]}. Відповідь {url, token, expires_in_s, bot_enabled}. Дійсне 30 хвилин. |
| GET | /bot | {username, url, enabled} |
Приклади
curl
curl -s https://svitlopulse.andrewboyko.name/api/v1/summary
curl -s https://svitlopulse.andrewboyko.name/api/v1/oblasts | jq '.oblasts[] | {slug, state, off_share}'
curl -s "https://svitlopulse.andrewboyko.name/api/v1/history/map?at=2026-11-04T10:00:00Z"JavaScript
const r = await fetch('/api/v1/oblasts');
const { oblasts } = await r.json();
const off = oblasts.filter((o) => o.state === 'off' || o.state === 'emergency');
// live updates: refetch when the server recomputes (~30 s)
const es = new EventSource('/api/v1/stream');
es.addEventListener('snapshot', () => refresh());Фрагмент відповіді /summary
{
"demo": false,
"rev": 1280,
"at": "2026-11-04T22:11:39+02:00",
"fact_enabled": true,
"fact_delay_min": 30,
"summary": { "groups": 324, "groups_off": 52, "oblasts_affected": 20, "emergency": false },
"operators_total": 25, "operators_fresh": 23, "oblasts_total": 27
}Числа вище — ілюстрація формату, а не реальні дані.
Правила приватності
- Публічні дані агреговані до рівня черги й області.
- Індивідуальні сигнали з’являються лише від 5 різних джерел і з затримкою не менше 30 хвилин (поле fact_delay_min).
- Немає шарів підстанцій чи ліній електропередач.
- Обговорення відхиляють повідомлення про обстріли та координати.
Чесні застереження
- Це не офіційне джерело і не гарантія подачі світла. Первинні дані належать операторам.
- Формат API v1 може розширюватися новими полями. Не покладайтеся на відсутність невідомих полів.
- Не робіть із нього систему автоматичних рішень там, де від цього залежить безпека людей.
- Поважайте ліміти. Для частих оновлень використовуйте /stream і ETag, а не опитування.
- Потрібні вищі квоти чи вебхуки? Є ключі (заголовок X-API-Key або Authorization: Bearer): Для розробників. Бейджі, картку для iframe й конфіг Home Assistant генерує сторінка «Віджети і бейджі».