Эндпоинты API v3
Все пути начинаются с /api/v3, каждый запрос требует заголовок X-API-Key и область доступа, указанную рядом с маршрутом. Основы авторизации — в разделе Внешний API.
Пользователи
GET /users — список
Область: users:read.
| Параметр | Тип | По умолчанию | Что делает |
|---|---|---|---|
limit | int, 1..500 | 100 | размер страницы |
offset | int | 0 | смещение |
status | string | — | фильтр по статусу: active, disabled и т. д. |
search | string | — | поиск по части username, email или uuid |
[
{
"uuid": "a2e...",
"username": "alice",
"status": "active",
"traffic_limit_bytes": 107374182400,
"used_traffic_bytes": 52013875200,
"expire_at": "2026-06-01T00:00:00Z",
"online": true,
"short_uuid": "AbCdEf123",
"subscription_url": "https://sub.example.com/AbCdEf123"
}
]GET /users/{uuid} — карточка
Область: users:read. Вернёт объект пользователя или 404.
short_uuid и subscription_url — идентификатор и ссылка подписки из панели. Ссылка берётся из последнего синка с панелью; пока пользователь не синхронизирован, поле будет null. Ссылка даёт доступ к конфигам, не публикуйте её.
POST /users — создать
Область: users:write.
{
"username": "alice",
"expire_at": "2026-06-01T00:00:00Z",
"traffic_limit_bytes": 107374182400,
"traffic_limit_strategy": "MONTH",
"hwid_device_limit": 3,
"description": "Создан из CI",
"telegram_id": 123456789,
"email": "alice@example.com",
"tag": "vip",
"status": "active",
"external_squad_uuid": "3f2c...",
"active_internal_squads": ["a1b2...", "c3d4..."]
}external_squad_uuid и active_internal_squads необязательны; UUID сквадов — из GET /squads/external и GET /squads/internal (см. ниже).
Ответ — 201:
{
"success": true,
"message": "User alice created",
"uuid": "a2e...",
"short_uuid": "AbCdEf123",
"subscription_url": "https://sub.example.com/AbCdEf123"
}Пользователь сразу пишется в базу админки, так что GET /users/{uuid} работает без ожидания синка. Если локальная база недоступна, uuid может прийти null — пользователь появится после следующего синка.
Остальные действия
| Эндпоинт | Метод | Область | Что делает |
|---|---|---|---|
/users/{uuid}/enable | POST | users:write | включить |
/users/{uuid}/disable | POST | users:write | отключить, можно передать {"reason": "..."} |
/users/{uuid}/reset-traffic | POST | users:write | обнулить счётчики трафика |
/users/{uuid} | DELETE | users:delete | удалить |
Массовые операции
Все принимают {"uuids": ["...", "..."]}, до 500 записей за раз.
{
"success": 498,
"failed": 2,
"errors": [
{"uuid": "...", "error": "not found"}
]
}| Эндпоинт | Область |
|---|---|
POST /users/bulk/enable | bulk:write |
POST /users/bulk/disable | bulk:write |
POST /users/bulk/delete | bulk:write |
POST /users/bulk/reset-traffic | bulk:write |
У массовых операций свой лимит запросов — API_V3_RATE_BULK_PER_MIN, по умолчанию 10 в минуту.
Ноды
| Эндпоинт | Метод | Область | Что делает |
|---|---|---|---|
/nodes | GET | nodes:read | список |
/nodes/{uuid} | GET | nodes:read | карточка |
/nodes/{uuid}/enable | POST | nodes:write | включить |
/nodes/{uuid}/disable | POST | nodes:write | отключить |
/nodes/{uuid}/restart | POST | nodes:write | перезапустить |
/nodes/sync | POST | nodes:write | синхронизировать список нод с панелью |
/nodes/{uuid}/agent-token/generate | POST | nodes:token | сгенерировать (перевыпустить) токен агента |
/nodes/{uuid}/agent-token/revoke | POST | nodes:token | отозвать токен агента |
{
"uuid": "...",
"name": "eu-west-1",
"address": "1.2.3.4",
"port": 62050,
"is_disabled": false,
"is_connected": true,
"users_online": 42
}Хосты
| Эндпоинт | Метод | Область |
|---|---|---|
/hosts | GET | hosts:read |
/hosts/{uuid} | GET | hosts:read |
Поля повторяют объекты хостов панели Remnawave: uuid, remark, address, port, sni, host, is_disabled, alpn, fingerprint.
Сквады
Область: users:read. Списки берутся живьём из панели Remnawave — чтобы взять UUID для external_squad_uuid и active_internal_squads при создании пользователя.
| Эндпоинт | Метод | Что отдаёт |
|---|---|---|
/squads/internal | GET | внутренние сквады: uuid, name, members_count, inbounds (uuid, tag) |
/squads/external | GET | внешние сквады: uuid, name, members_count |
[
{
"uuid": "3f2c...",
"name": "Standard",
"members_count": 128,
"inbounds": [{"uuid": "a1b2...", "tag": "VLESS-Reality"}]
}
]Панель недоступна — 503.
Нарушения
GET /violations — список
Область: violations:read. Свежие сверху.
| Параметр | Тип | По умолчанию | Что делает |
|---|---|---|---|
limit | int, 1..500 | 100 | размер страницы |
offset | int | 0 | смещение |
user_uuid | string | — | по конкретному пользователю |
telegram_id | int | — | по Telegram-идентификатору клиента |
min_score | float | — | нижняя граница скоринга |
recommended_action | string | — | hard_block, temp_block, monitor |
resolved | bool | — | true — решение принято, false — открытые |
date_from, date_to | ISO datetime | — | границы по времени обнаружения |
[
{
"id": 9123,
"user_uuid": "...",
"username": "alice",
"score": 87.5,
"confidence": 0.9,
"recommended_action": "hard_block",
"action_taken": null,
"reasons": ["4 одновременных подключения из 3 стран"],
"ip_addresses": ["1.2.3.4"],
"countries": ["RU", "NL"],
"detected_at": "2026-06-07T11:50:00+00:00",
"notified_at": null
}
]notified_at — когда клиенту отправили предупреждение по этому нарушению; null — не предупреждали.
GET /violations/summary — вердикт по клиенту
Область: violations:read. Отвечает на один вопрос: можно ли доверять этому человеку. Нужна интеграциям, которые принимают решение — выдавать ли триал, промокод, продление — и которым незачем разбирать список нарушений.
| Параметр | Тип | По умолчанию | Что делает |
|---|---|---|---|
telegram_id | int | — | клиент по Telegram-идентификатору |
user_uuid | string | — | клиент по UUID панели |
window_days | int, 1..365 | 30 | за какой срок считаем |
Нужен telegram_id или user_uuid, иначе 422.
{
"user_uuid": "...",
"telegram_id": 366945364,
"window_days": 30,
"level": "warned",
"violations": 2,
"max_score": 74.0,
"last_detected_at": "2026-09-20T10:00:00+00:00",
"last_action": null,
"whitelisted": false,
"notice": {
"violation_id": 9123,
"kind": "device",
"subject": "Подписка используется с нескольких устройств",
"body": "Мы заметили…",
"sent_at": "2026-09-20T10:05:00+00:00"
}
}notice — последнее предупреждение, которое клиент действительно получил: тема и текст ровно в том виде, в каком ушли, даже если шаблон потом поправили; null, если не предупреждали. body — простой текст для показа как есть: разметка Telegram снята, у ссылок адрес в скобках. kind — вид нарушения, по шаблону которого писали: default, temporal, geo, asn, profile, device, hwid, user_agent, torrent, traffic_rate.
level — три значения: clean (нарушений за окно нет либо человек в белом списке), warned (нарушения есть, мер не принимали), limited (по последнему нарушению применили блокировку или ограничение скорости).
Аннулированные нарушения не считаются — детектор ошибся, и человек тут ни при чём. Белый список перебивает всё: его ставят руками, уже зная про нарушения, и интеграция не должна наказывать того, кого оператор оправдал.
GET /violations/{id} — карточка
Область: violations:read. Отдаёт полную раскладку по анализаторам (temporal_score, geo_score, asn_score, profile_score, device_score, hwid_score, user_agent_score), собранные свидетельства (cities, asn_types, os_list, client_list), флаги (impossible_travel, is_mobile, is_datacenter, is_vpn) и разбор (action_taken, action_taken_at, admin_comment).
Обращение во внешнюю поддержку
POST /support-events
Область: enforcement:support. Бот или helpdesk сообщает, что клиент написал в поддержку. Если для его нарушения ждёт отложенный шаг с включённой проверкой поддержки, при наступлении срока шаг будет пропущен с причиной support_contacted.
Заголовок Idempotency-Key обязателен и должен быть уникальным для события в пределах API-ключа. Повтор с тем же значением безопасно возвращает 202 и duplicate: true.
{
"source": "telegram-support",
"kind": "customer_message",
"occurred_at": "2026-09-26T10:30:00Z",
"user": { "telegram_id": 123456789 },
"ticket_id": "ticket-42",
"metadata": { "queue": "billing" }
}В user нужен хотя бы один идентификатор: user_uuid, telegram_id, email или username. Если передано несколько, все должны указывать на одного пользователя. Ответы: 404 — пользователь не найден, 409 — идентификатор неоднозначен, 422 — некорректный запрос или время события более чем на пять минут в будущем.
Для отдельного Telegram-бота обычно достаточно telegram_id. Событие хранится в Admin; внешней системе не нужен доступ к базе или тикетам Bedolaga.
Статистика
GET /stats, область stats:read:
{
"users_total": 3450,
"users_active": 2980,
"users_disabled": 370,
"users_online": 512,
"nodes_total": 12,
"nodes_online": 11,
"traffic_total_bytes": 48934567890123
}Общие правила
- Время всегда в ISO 8601 и в UTC
- Трафик — в байтах, без пересчёта в мегабайты
uuid— идентификаторы панели Remnawave, не путайте с внутренними id- Неизвестные поля на входе игнорируются, на выходе не появляются: модели строгие