| Аспект |
Правило |
| Версия |
Префикс /api/v1 (админ), /portal/v1 (кабинет). Несовместимые изменения — только новой версией |
| Формат |
JSON, snake_case, время — RFC 3339 UTC |
| Аутентификация |
Authorization: Bearer <access JWT>; scope admin для /api, client для /portal (Аутентификация) |
| Пагинация |
Курсорная: ?limit=&cursor=; ответ { "items": [...], "next_cursor": "..." }. Offset-пагинация не используется |
| Фильтрация |
Query-параметры по именам полей: GET /api/v1/inbounds?node_id=… |
| Частичное обновление |
PATCH с merge-семантикой: присланные поля обновляются, отсутствующие не трогаются |
| Ошибки |
RFC 9457 application/problem+json: { "type", "title", "status", "detail", "errors": {поле: причина} } |
| Идемпотентность |
Заголовок Idempotency-Key обязателен для POST /portal/v1/checkout |
Спецификация OpenAPI генерируется из кода и доступна на /api/v1/openapi.json; типы фронтенда генерируются из неё.
| Метод |
Путь |
Примечание |
| GET |
/api/v1/auth/methods |
Без аутентификации: включённые методы входа + setup_required (политика) |
| POST |
/api/v1/setup |
{token, email, password} → первый owner; существует только в bootstrap-режиме (Первый администратор) |
| POST |
/api/v1/auth/login |
email + пароль → пара JWT; 404 при выключенном методе |
| GET |
/api/v1/auth/oauth/{provider}/redirect |
|
| GET |
/api/v1/auth/oauth/{provider}/callback |
|
| POST |
/api/v1/auth/refresh |
Ротация refresh-токена |
| POST |
/api/v1/auth/logout |
Отзыв сессии |
| GET |
/api/v1/auth/me |
|
| Метод |
Путь |
| GET · POST |
/api/v1/admins |
| GET · PATCH · DELETE |
/api/v1/admins/{id} |
| Метод |
Путь |
Примечание |
| GET · POST |
/api/v1/nodes |
В ответе — admin_status, связность, ревизии |
| GET · PATCH · DELETE |
/api/v1/nodes/{id} |
DELETE отклоняется, если нода в цепочке |
| POST |
/api/v1/nodes/{id}/enroll-token |
Выпуск/перевыпуск одноразового токена |
| POST |
/api/v1/nodes/{id}/restart-xray |
Команда агенту через стрим |
| GET |
/api/v1/nodes/{id}/logs |
Снапшот: `?source=agent |
| GET |
/api/v1/nodes/{id}/logs/stream |
SSE, live-tail |
Отдельных эндпоинтов статуса/системных метрик нет: они входят в представление ноды (последний StatusReport агента).
| Метод |
Путь |
| GET · POST |
/api/v1/inbound-profiles |
| GET · PATCH · DELETE |
/api/v1/inbound-profiles/{id} |
| GET · POST |
/api/v1/inbounds |
| GET · PATCH · DELETE |
/api/v1/inbounds/{id} |
GET /api/v1/inbounds?node_id= — инбаунды ноды; ?profile_id= — все привязки профиля. Плоская коллекция вместо вложенной (/nodes/{id}/inbounds): на инбаунды ссылаются группы доступа и цепочки, канонический URL не должен зависеть от ноды.
| Метод |
Путь |
Примечание |
| GET · POST |
/api/v1/chains |
Хопы — массив в теле |
| GET · PATCH · DELETE |
/api/v1/chains/{id} |
PATCH с hops[] полностью заменяет состав |
Хопы не имеют отдельных эндпоинтов: состав цепочки — упорядоченный список, декларативная замена целиком проще и безопаснее адресации по позициям.
| Метод |
Путь |
Примечание |
| GET · POST |
/api/v1/certificates |
kind: acme → запускает выпуск |
| GET · PATCH · DELETE |
/api/v1/certificates/{id} |
|
| POST |
/api/v1/certificates/{id}/renew |
Принудительное продление |
| GET · POST |
/api/v1/dns-providers |
|
| GET · PATCH · DELETE |
/api/v1/dns-providers/{id} |
|
| POST |
/api/v1/dns-providers/{id}/check |
Тестовая TXT-запись |
| GET · POST |
/api/v1/acme-accounts |
|
| GET · DELETE |
/api/v1/acme-accounts/{id} |
|
| Метод |
Путь |
Примечание |
| GET · POST |
/api/v1/access-groups |
|
| GET · PATCH · DELETE |
/api/v1/access-groups/{id} |
inbound_ids[] — полная замена |
| Метод |
Путь |
Примечание |
| GET · POST |
/api/v1/clients |
?status= (очередь заявок: pending) |
| GET · PATCH · DELETE |
/api/v1/clients/{id} |
|
| POST |
/api/v1/clients/{id}/approve |
Режим application: pending → active |
| POST |
/api/v1/clients/{id}/reject |
pending → rejected |
| GET · POST |
/api/v1/subscriptions |
?client_id=, ?status= |
| GET · PATCH · DELETE |
/api/v1/subscriptions/{id} |
PATCH: продление, лимит, статус |
| POST |
/api/v1/subscriptions/{id}/rotate-credentials |
Перевыпуск ключей |
| GET |
/api/v1/subscriptions/{id}/usage |
`?from=&to=&granularity=hour |
| GET |
/api/v1/subscriptions/{id}/link |
Ссылка /sub/{token} |
| Метод |
Путь |
| GET · POST |
/api/v1/plans |
| GET · PATCH · DELETE |
/api/v1/plans/{id} |
| GET · POST |
/api/v1/payment-providers |
| GET · PATCH · DELETE |
/api/v1/payment-providers/{id} |
| GET |
/api/v1/payments |
| GET |
/api/v1/payments/{id} |
| Метод |
Путь |
Примечание |
| GET |
/api/v1/stats/overview |
Ноды, активные подписки, трафик за период |
| GET |
/api/v1/audit-log |
?actor_id=&entity_type=&entity_id=&from=&to= |
| Метод |
Путь |
Примечание |
| GET |
/sub/{token} |
Конфиг подписки; формат — по User-Agent. Без версии: URL живёт в клиентских приложениях годами |
| POST |
/webhooks/payments/{provider} |
Вебхуки агрегаторов; проверка подписи — в адаптере (Платежи) |
| Метод |
Путь |
Примечание |
| GET |
/portal/v1/auth/methods |
Без аутентификации: методы входа + режим регистрации |
| POST |
/portal/v1/auth/register |
{email, password}; 404 при closed, 409 — email занят (Саморегистрация) |
| POST |
/portal/v1/auth/login |
email + пароль |
| POST |
/portal/v1/auth/magic-link |
Отправка ссылки на email |
| POST |
/portal/v1/auth/callback |
Токен из ссылки → пара JWT; первое использование подтверждает email |
| GET |
/portal/v1/auth/oauth/{provider}/redirect |
|
| GET |
/portal/v1/auth/oauth/{provider}/callback |
Вход или регистрация (по режиму) |
| POST |
/portal/v1/auth/refresh |
|
| GET |
/portal/v1/me |
Клиент + его подписки |
| GET |
/portal/v1/subscriptions/{id}/usage |
Только своя подписка |
| POST |
/portal/v1/subscriptions/{id}/rotate-credentials |
|
| GET |
/portal/v1/subscriptions/{id}/link |
|
| GET |
/portal/v1/plans |
Только неархивные |
| GET |
/portal/v1/payment-methods |
Включённые провайдеры |
| POST |
/portal/v1/checkout |
{plan_id, provider_id, subscription_id?} → URL чекаута |