API сервера для ботів
Клієнтський API Millida Hosting: видача ключа, дозволи, керування сервером і стрімінг консолі з вашого бота або скрипта.
Оновлено 13 жовтня 2026 р.
Усе, що вміє панель, можна робити зі свого коду: запускати сервер за розкладом, показувати статус у Discord, надсилати команди з бота.
Ключ
API доступний на будь-якому платному тарифі — там само, де файли, SFTP і командний доступ. На безплатному тарифі ключ не видають: ключ — це той самий спільний доступ, лише для бота.
Розділ «Гравці та доступ» → «API-ключі» → «Видати». Перевірте, що дозволено ключу — права ті самі, що й у спільного доступу.
Ключ показують один раз: ми зберігаємо лише його відбиток. Якщо загубите — видайте новий, а старий відкличте.
Ключ передають у заголовку Authorization: Bearer mhk_live_....
Методи
Базова URL-адреса — https://millida.net/v2/hosting/api.
| Метод | Що робить | Потрібний дозвіл |
|---|---|---|
GET /server | Картка сервера | console |
GET /status | Статус і онлайн | console |
POST /start | Запуск | start |
POST /stop | Зупинка | start |
POST /restart | Перезапуск | start |
POST /command | Команда в консоль | console |
GET /console | Живий лог (SSE) | console |
GET /files?path= | Список файлів | files |
GET /files/configs | Які конфіги читає форма | files |
GET /files/config?path= | Налаштування файлу з типами | files |
POST /files/config | Змінити налаштування файлу | files |
GET /backups | Список резервних копій | backups |
POST /backups | Створити резервну копію | backups |
GET /antibot | Налаштування антибота, бекенди та правила фаєрвола | protection |
PUT /antibot | Змінити налаштування захисту | protection |
GET /antibot/overview?range= | Підключення та відмови за hour, day або week | protection |
POST /antibot/backends | Додати бекенд {"address":"host:port","label":"..."} | protection |
DELETE /antibot/backends/{id} | Видалити бекенд | protection |
POST /antibot/rules | Правило фаєрвола {"kind":"allow"|"deny","cidr":"1.2.3.0/24"} | protection |
DELETE /antibot/rules/{id} | Видалити правило | protection |
POST /antibot/verify-domain/check | Перевірити DNS для домену вашої сторінки верифікації | protection |
Приклад: запустити сервер і дочекатися, коли він вийде в онлайн
KEY="mhk_live_xxx"
API="https://millida.net/v2/hosting/api"
curl -sX POST "$API/start" -H "Authorization: Bearer $KEY"
until curl -s "$API/status" -H "Authorization: Bearer $KEY" | grep -q RUNNING; do
sleep 5
done
echo "server online"
Резервні копії створюються у фоні
POST /backups одразу повертає {"id":"..."}, а сам архів збирається на вузлі: світ на кілька гігабайтів збирається хвилинами. Готовність перевіряйте в GET /backups за полем status: pending — ще збирається, ready — збережено у сховищі (саме тоді з'являється справжній sizeMb), failed — не вдалося зібрати.
ID=$(curl -sX POST "$API/backups" -H "Authorization: Bearer $KEY" | jq -r .id)
until curl -s "$API/backups" -H "Authorization: Bearer $KEY" \
| jq -e --arg id "$ID" '.[] | select(.id==$id) | select(.status=="ready")' >/dev/null; do
sleep 15
done
echo "backup ready"
Поки резервна копія триває, створити другу на тому самому сервері не можна — вузол робить їх по одній.
Жива консоль
GET /console повертає потік Server-Sent Events: кожен рядок приходить із префіксом data:. WebSocket не потрібен — SSE проходить крізь будь-який проксі.
Що варто знати
- Кожна дія за ключем потрапляє в лог сервера з автором «API key N». Саме те, що потрібно, коли серверами керують і люди, і боти.
- Обмеження частоти рахується на ключ, а не на адресу: зміна IP не обходить ліміт, а сусід в офісній мережі його не витрачає. Для звичайної автоматизації його щедро, але опитування статусу раз на секунду в нього впреться — достатньо раз на 10–15 секунд. Потік консолі можна відкривати до десяти разів на хвилину: тримайте одне з'єднання замість того, щоб відкривати нове на кожне повідомлення.
- Ключ перестає працювати одразу, якщо сервер призупинено або тариф більше не оплачено. Відкликати його вручну для цього не потрібно.
- До п'яти ключів на сервер. Непотрібні відкликайте.
Захист від ботів
GET /antibot повертає налаштування у двох полях. config — власні налаштування сервера; поки їх немає, там null, і сервер захищений типово (поле default). effective присутнє завжди: це налаштування, які діють зараз або з якими сервер почне працювати після першого редагування — читайте значення з нього.
PUT /antibot приймає лише ті поля, які ви хочете змінити:
curl -sX PUT "$API/antibot" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"preset":"balanced"}'
Рівні (preset): off, under_attack, balanced, aggressive, custom. Рівень сам розгортається у значення перевірок, тож для ручного налаштування вибирайте custom і надсилайте перевірки: checkCaptcha, checkPhysics, checkKeepAlive, checkTeleport, checkBrand, checkPing, checkTransfer, checkClientSettings — кожна off, under_attack або always. Списки адрес (vpnMode, datacenterMode, torMode) — off, log або block. Геофільтр — geoMode (off, allow, deny) і geoCountries (коди країн, наприклад ["RU","BY"]).
Секрет форвардингу не видають і не змінюють через API: його показують лише власнику в панелі.
Налаштування конфігів
GET /files/config?path=server.properties повертає розібраний файл — кожен запис із типом, поточним значенням і позначкою «потрібен перезапуск»:
{
"path": "server.properties",
"format": "properties",
"options": [
{ "key": "pvp", "type": "boolean", "value": "true", "owner": "sync", "requiresRestart": false },
{ "key": "difficulty", "type": "select", "value": "normal", "values": ["peaceful", "easy", "normal", "hard"], "owner": "sync", "requiresRestart": false },
{ "key": "server-port", "type": "integer", "value": "25565", "owner": "platform", "requiresRestart": true }
]
}
owner підказує, що можна робити із записом: platform — значення задає хостинг, редагування відхиляються; sync — запис є і в панелі, і у файлі; file — про нього знає лише файл.
Запис змінює тільки ті ключі, які ви надіслали; усе інше у файлі залишається недоторканим:
curl -sX POST "$API/files/config" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"path":"server.properties","values":{"pvp":"false","difficulty":"hard"}}'
Форма читає .properties, .yml/.yaml і .toml — зокрема конфіги плагінів, про які панель нічого не знає: тип поля визначається зі значення. Вкладені ключі адресуються через крапку: settings.bungeecord, advanced.compression-threshold.
Увесь файл, як і раніше, доступний через GET/PUT /files/content?path= — обидва шляхи пишуть в одне місце.
Готовий клієнт на Node.js і Python
Нижче наведено мінімальний клієнт: він перевіряє статус, запускає сервер і пише в чат. Ключ береться зі змінної середовища MILLIDA_KEY — не вставляйте його в код, який потрапляє в git. Відповідь про помилку — це JSON із полем message; саме його має логувати ваш бот.
Node.js 18+ (вбудований fetch):
const API = 'https://millida.net/v2/hosting/api';
const KEY = process.env.MILLIDA_KEY;
async function call(method, path, body) {
const res = await fetch(`${API}${path}`, {
method,
headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${await res.text()}`);
return res.status === 204 ? null : res.json();
}
const status = await call('GET', '/status');
if (status.status !== 'RUNNING') await call('POST', '/start');
await call('POST', '/command', { command: 'say Hello from the bot' });
Python 3 з бібліотекою requests, а також читання живої консолі:
import os
import requests
API = "https://millida.net/v2/hosting/api"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['MILLIDA_KEY']}"
def call(method, path, body=None):
res = session.request(method, API + path, json=body, timeout=15)
res.raise_for_status()
return res.json() if res.content else None
status = call("GET", "/status")
if status["status"] != "RUNNING":
call("POST", "/start")
call("POST", "/command", {"command": "say Hello from the bot"})
with session.get(API + "/console", stream=True, timeout=None) as stream:
for line in stream.iter_lines(decode_unicode=True):
if line and line.startswith("data:"):
print(line[5:].strip())
