Публічний API
Загальне
Вимкнений за замовчуванням: картка «Локальний API» на сторінці «Дії» вмикає його й показує ключ. Працює на порту сервера оверлеїв (за замовчуванням 5233) лише на цьому ПК.
- Усі запити мають заголовок
X-Spalakh-Key: <ключ>. ЗаголовокOrigin(запит із сторінки в браузері) відхиляється. Ключ — 256 випадкових біт; перевипуск обриває старі інтеграції. Старе ім’я заголовкаX-BotValeriy-Keyприймається далі, тож наявні інтеграції не треба міняти.
Версія API: 1. Усі адреси мають префікс /api/v1. Старі адреси без версії (/api/actions, /api/ws) лишаються псевдонімами v1, тож Stream Deck і ранні скрипти працюють без змін. Правило сумісності: у v1 можуть з'являтись нові поля, події й адреси, але наявні не зникають і не міняють змісту; несумісна зміна вийде як /api/v2, а v1 житиме далі.
GET /api/v1→{"name","version","endpoints","events"}: версія й перелік адрес та типів подій, які знає ця збірка.GET /api/v1/actions→[{"id","name"}]POST /api/v1/actions/{назва-або-id}/run, тіло (до 4 КБ, необов'язкове){"user","input"}→202/404- WebSocket
/api/v1/ws: першим приходитьstate(apiVersion,live: true/false/null,actions), далі події:stream.online,stream.offline;action.finished(name,source,user,test,failed,ms);event.follow,event.subscription,event.resub,event.gift-sub,event.raid,event.redeem,event.chat,event.donation,event.bits,event.power-up: події каналу, ті самі, що отримують оверлеї й модулі (data:user,platform(twitch,kick,youtube; порожньо для донату Donatello) іextrasіз деталями події; тестові позначеніextras.test; повтори історії оверлею не надсилаються).event.custom: подія, яку надіслала зовнішня програма (див. нижче):data—name,user,data(поля).variable.changed: глобальну змінну задано чи прибрано (чи цим API, чи дією, чи з екрана «Змінні»):data—name,value(null, якщо прибрано). Змінні глядачів у стрічку не йдуть. Повідомлення — JSON{"type","ts","data"}. Невідомі типи слухач має ігнорувати: їх додаватимуть. Повільний слухач губить найстаріші повідомлення.
Власна подія від зовнішньої програми
POST /api/v1/events, тіло (до 4 КБ) {"name","user","data"}: 202 — прийнято, 400 — некоректне тіло ({"error"}), 401/403/404 — як у решти адрес, 413 — тіло завелике, 429 — забагато записів (до 30 на секунду на весь API).
name— обов'язкова назва латиницею:a-z,0-9,_,.,-, до 40 символів (регістр не має значення, зберігається малими).user— необов'язково, до 50 символів; без ньогоapi. Іде в$(user).data— необов'язково, плаский об'єкт: до 20 ключівa-z0-9_(до 40 символів), значення — рядок, число чиtrue/false(до 500 символів, довші обрізаються); вкладені об'єкти й масиви відхиляються.
Подія робить дві речі: з'являється в стрічці як event.custom ({"name","user","data"}) для всіх слухачів сокета і запускає тригери «Зовнішня подія» з тією ж назвою (порожня назва в тригері — будь-яка подія). Дія тригера отримує теги $(name), $(user) і $(data.ключ) для кожного поля; $(input) — назва події. Подія не потрапляє в оверлеї й модулі.
curl -X POST http://127.0.0.1:5233/api/v1/events -H "X-Spalakh-Key: $KEY" -H "Content-Type: application/json" -d '{"name":"game.death","user":"alice","data":{"count":7,"boss":"Knight"}}'Мобільна панель
http://127.0.0.1:<порт>/panel: сторінка з кнопками дій, у яких у редакторі дії увімкнено «Показувати в мобільній панелі» (типово вимкнено, тож панель не відкриває всі дії). Колір кнопки -- #RRGGBB у тому ж редакторі, групи -- папки дій. Ключ той самий, що в API: вводиться на сторінці раз і запам'ятовується в цьому браузері; новий ключ у застосунку розлогінює всі панелі. Запуск іде звичайним ланцюжком, в історії джерело «Панель». Межа частоти спільна з API (30 записів на секунду). Запит зі сторінки іншого сайту (чужий Origin) відхиляється.
З телефона: на картці «Локальний API» увімкніть «Доступ із телефона в локальній мережі» й перезапустіть застосунок. Тоді сервер слухає й локальну мережу, але ззовні відкрито лише /panel: оверлеї, API, аудіо й модулі лишаються доступні тільки з цього комп'ютера. Під прапорцем видно адреси для телефона (IP комп'ютера в мережі). Трафік не шифрується: вмикайте лише вдома. QR-коду поки нема, адресу треба набрати.
Вебхук стороннього сервісу
Сервіси на кшталт донат-платформ, GitHub чи IFTTT не вміють свої заголовки й шлють вкладений JSON. Для них є POST /api/v1/hook/{назва}?key=<ключ>: ключ у адресі (заголовок X-Spalakh-Key теж підходить), {назва} — як name вище.
- Тіло до 4 КБ: JSON або форма (
application/x-www-form-urlencoded). Вкладене сплощується:{"data":{"amount":5,"tags":["a","b"]}}дає$(data.data_amount)=5і$(data.data_tags_1)=b; символи позаa-z0-9_стають_, ключ до 40 символів. Поле форми, значення якого — JSON, сплощується так само (data={"amount":5}→data_amount). - Береться не більше 20 полів, решта мовчки відкидається.
$(user)— полеuserз тіла, інакшеwebhook.- Далі все як у власної події: стрічка
event.custom, тригер «Зовнішня подія» з цією назвою, ті самі коди відповіді.
curl -X POST "http://127.0.0.1:5233/api/v1/hook/kofi?key=$KEY" -H "Content-Type: application/json" -d '{"user":"bob","amount":5}'Ключ у посиланні потрапляє в журнали стороннього сервісу. Якщо він кудись витік, змініть ключ у налаштуваннях API. Сервер слухає лише цей комп'ютер (127.0.0.1), тож щоб сервіс з інтернету достукався, потрібен тунель (ngrok, Cloudflare Tunnel), який ви налаштовуєте самі.
Слухач на Node (пакет ws; браузерна сторінка не підходить: Origin відхиляється):
import WebSocket from "ws";
const ws = new WebSocket("ws://127.0.0.1:5233/api/v1/ws", { headers: { "X-Spalakh-Key": process.env.KEY } });
ws.on("message", (raw) => {
const { type, data } = JSON.parse(raw);
if (type === "event.custom") console.log(data.name, data.data);
});Змінні
Глобальні змінні дій (ті, що в кроці «Змінна» і тегу $(var.назва)) читаються й пишуться тим самим ключем. Змінні глядачів через API недоступні.
GET /api/v1/variables/{назва}→200 {"name","value"}або404, якщо такої змінної немає (чи бота ще немає).PUT /api/v1/variables/{назва}, тіло (до 4 КБ){"value","mode"}→200 {"name","value"}з новим значенням.value— рядок, число чиtrue/false;mode—set(типово, задати) абоadd(додати число; не число —400).
Межі ті самі, що в VariableBank: назва a-z, 0-9, _ до 40 символів, значення до 500 символів (довші обрізаються), до 500 глобальних змінних; порушення — 400 з {"error"}. Записи рахуються в загальний ліміт 30 на секунду (429).
curl -X PUT http://127.0.0.1:5233/api/v1/variables/deaths -H "X-Spalakh-Key: $KEY" -H "Content-Type: application/json" -d '{"value":1,"mode":"add"}'
curl http://127.0.0.1:5233/api/v1/variables/deaths -H "X-Spalakh-Key: $KEY"const res = await fetch("http://127.0.0.1:5233/api/v1/variables/deaths", { headers: { "X-Spalakh-Key": KEY } });
const { value } = await res.json(); // Node 18+; з браузера не працює (Origin відхиляється)Команди по сокету
Той самий сокет /api/v1/ws приймає й команди, тож один зв'язок і слухає, і керує (без окремих HTTP-запитів). Клієнт шле текстове повідомлення (до 4 КБ; більше — сокет закривається з кодом 1009), бот відповідає повідомленням ack лише цьому клієнту:
{"type":"run","action":"назва-або-id","user":"…","input":"…","id":"будь-що"}— те саме, щоPOST …/actions/{…}/run;{"type":"event","name":"game.death","user":"…","data":{…},"id":"…"}— те саме, щоPOST …/events(правила й межі ті самі).
Відповідь: {"type":"ack","data":{"id":"…","ok":true,"error":null}}; id повертається як надіслано (до 50 символів, необов'язковий), error — причина (action not found, rate limit, bad json, unknown type або текст перевірки події). Помилка не закриває сокет. Команди рахуються в той самий ліміт 30 на секунду.
ws.on("open", () => {
ws.send(JSON.stringify({ type: "event", id: "1", name: "game.death", data: { count: 7 } }));
ws.send(JSON.stringify({ type: "run", id: "2", action: "Привітання" }));
});
// далі в ws.on("message"): { type: "ack", data: { id: "1", ok: true, error: null } }