meduzavpn
Контракт кандидата · границы первого выпуска

Meduza Business API

Управляйте компаниями, участниками, доступом к VPN и маршрутами через тот же API, которым пользуется корпоративный кабинет.

Это контракт текущей корпоративной ветки. Готовность обработчика не означает публикацию в production: внешние платежи, выдача VPN, email и применение политик работают при подключённых адаптерах окружения.

Первый выпуск: 169 методов текущего контракта — не 169 из 191 готовых требований. Черновик использует другие пути и процессы. Полная матрица первого выпуска: SSO/SCIM, перенос владения, развёртывание прошивок роутеров, экспорт конфигураций и юридические реквизиты для счетов исключены. Каналы notification-channels — только legacy-инвентарь: контракт и доставка email/webhook/in_app исключены из первого выпуска. Семь типов алертов доступны в мониторинге, аудите и API; доставка через отдельный подписанный webhooks API остаётся в объёме выпуска. Роутеры и ресурсы пока являются инвентарём; billing-profile — хранилищем метаданных без связи со счетами.

Авторизация и права

Базовый путь: /api/business/v1. Интерфейс использует текущую пользовательскую сессию. Для автоматизации создайте API-клиента в кабинете компании и сохраните секрет при выдаче.

POST /api/business/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_SECRET

Передавайте полученный токен в Authorization: Bearer TOKEN. Токен действует один час и только внутри компании, выдавшей клиента. Доступ отзывается при отключении клиента или прав создавшего его администратора.

Права

read — чтение; read write — чтение и управление. API-клиентами управляет вошедший пользователь. Бухгалтеру доступны счета и подписка, но не сотрудники и сети.

Повторные запросы

Для изменений используйте Idempotency-Key. Для редактирования передавайте If-Match: "3" с текущей версией объекта. При конфликте 412 перечитайте объект.

Оплата и выдача VPN

  1. Создайте компанию через POST /organizations из пользовательской сессии.
  2. Получите расчёт через subscription/quotes: количество VPN, период и операция purchase, renewal или upgrade.
  3. Передайте quote_id и payment_method: stripe_card в subscription/checkout.
  4. Ответ 202 означает подготовку счёта. Читайте invoices до появления payment_url; оплатите по ссылке.
  5. После подтверждения платёжного реестра подписка станет активной. Создавайте VPN с pricing_id из catalog/vpn-locations и обязательным Idempotency-Key.

Пакет — от 5 VPN. База за VPN: $5.99 в месяц или $54.99 в год. Скидка на пакет: 5–9 VPN — 5%, 10–99 — 10%, от 100 — 20%. Возврат браузера после оплаты не выдаёт доступ без проверки платежа.

Продление сохраняет количество и период. Увеличение пакета рассчитывает доплату за оставшийся срок. Для окончательного удаления сервера используйте POST /organizations/{organization_id}/vpns/{id}/retire с confirm: true и If-Match. Место освобождается после подтверждённого удаления, цена подписки не меняется. Назначение сотруднику передаётся как member_id; без него VPN доступен компании согласно назначениям доступа.

Маршруты и наборы трафика

Набор описывает сайты или сети, правило выбирает действие: конкретный VPN, напрямую либо запрет. Используйте страны и регионы из catalog/traffic-presets. В режиме first-match правила проверяются сверху вниз, максимум 128; у «Остального трафика» запрет недоступен.

Сохранение создаёт черновик. Выполните проверку, затем публикацию с If-Match. Проверяйте policy-deployments: постановка в очередь и подтверждённое применение устройством — разные состояния. Подключение к VPN выполняет клиентское приложение.

Роли, группы и устройства

GET /organizations/{id}/roles возвращает встроенные и собственные роли, определения разрешений и признак can_manage. Владелец создаёт собственную роль на основе администратора, сотрудника или финансовой роли, оставляя только нужные права. Назначение — через PATCH members/{id}: role и custom_role_id. Смена прав действует и на API-клиентов создавшего их пользователя.

Роль разрешает действия в кабинете. group_ids назначает сотруднику VPN и пакет маршрутизации; членство в группе не даёт административных прав. Роль владельца нельзя скопировать в собственную. Назначенную сотрудникам роль нельзя удалить.

Устройства получают display_name, владельца и сведения о VPN. PATCH devices/{id} меняет только название с проверкой If-Match. POST devices/{id}/revocations запрашивает отзыв; окончательный статус подтверждает узел. Собственные устройства доступны через /me/devices. Поле last_api_ip — адрес транспорта API, а не VPN-соединения. Название и модель, сообщённые приложением, не используются для авторизации.

Подключения и журнал направлений

GET /organizations/{id}/employee-analytics показывает наблюдаемые подключения, изменения состояния и почасовую историю за 7 дней. Пропущенное измерение не заменяется нулём; число сессий не является временем работы сотрудника.

GET /organizations/{id}/activity возвращает зарегистрированные узлом запросы соединений: запрошенный домен или IP, порт, протокол, время, решение, устройство и сотрудника. Фильтры: from, to, member_id, action, search; страницы — cursor и limit. Домен передан клиентом в запросе соединения, а не получен из расшифровки HTTPS.

Сбор по умолчанию выключен. Владелец меняет activity-settings через PATCH с {"enabled": true} и If-Match. Чтение требует activity.read. При включённом сборе приложение показывает уведомление сотруднику; выдача ключа требует актуального подтверждения X-Corporate-Activity-Version после проверки владельца ключа. Старый клиент не получает ключ для этого режима.

Хранение ограничено 7 днями и 100 000 событий на компанию; буфер узла — до 24 часов. coverage сообщает свежесть, недоступные устройства и потери буфера. Личные VPN, прямой трафик устройства, локальные блокировки до обращения к узлу, пути HTTPS, содержимое запросов и оценка продуктивности не записываются. Отключение сбора не восстанавливает пропущенную историю и не удаляет мгновенно ранее собранные записи: действует срок хранения.

Категории и время сетевой активности

Ответ журнала содержит analysis: распределение по категориям, сотрудникам и часам, основные назначения и число active_minutes. Сводки рассчитываются по всем сохранённым событиям выбранного периода, независимо от страницы исходного журнала. Фильтр category позволяет перейти к конкретным событиям.

Одна активная минута — уникальная минута сотрудника, в которую узел наблюдал запрос. Это не длительность просмотра сайта или работы: учитывается фоновый трафик, а категории могут пересекаться в одной минуте. Суммарное время рассчитывается отдельно и не складывается из категорий.

Владелец задаёт до 64 правил classification_rules в настройках журналирования: домен и категория. Они распространяются на поддомены и имеют приоритет над встроенным справочником. Неизвестные назначения остаются отдельной категорией. Текущие правила классифицируют весь выбранный период; ответ указывает версию классификации.

Обрабатываются назначения корпоративных соединений, а не содержимое HTTPS, полные URL или личный трафик. Подтверждение уведомления сохраняется один раз для сотрудника в компании; смена категорий, групп или режима сбора не требует повторного подтверждения того же уведомления. Признаки неполного покрытия и truncated нельзя трактовать как отсутствие активности.

Подписки на события

Создайте webhooks с публичным HTTPS URL на порту 443 и событиями audit.event, * или groups.created, members.updated и другими изменениями ресурсов. Секрет показывается только при создании или ротации.

Meduza-Signature: t=UNIX_SECONDS,v1=HEX_SIGNATURE
Meduza-Event-Id: EVENT_ID
Meduza-Delivery-Id: DELIVERY_ID

HEX_SIGNATURE = HMAC-SHA256(secret, timestamp + "." + RAW_JSON_BODY)

Проверяйте подпись по исходным байтам тела, допустимый возраст timestamp и повторение event ID. Во время ротации сохраните предыдущий секрет для уже поставленных в очередь событий. Успех — любой 2xx; остальные ответы повторяются с увеличением интервала, до восьми попыток. История и ручной повтор доступны через deliveries. Успешные и отменённые доставки хранятся до 30 дней, максимум 2 000 на webhook. Очередь и ошибки ограничены 1 000 событиями; при переполнении старые события удаляются, счётчик dropped_deliveries сообщает о потере. В этом случае синхронизируйте состояние через API.

Доставка выполняется как минимум один раз. Помимо изменений через API отправляются подтверждённые изменения счетов (invoices.updated), подписок (subscriptions.updated), готовности VPN (vpns.updated) и алерты (alerts.created). Повторный опрос без изменения состояния не создаёт новое событие. Это не поток сетевого трафика. Приватные IP, перенаправления и обращения к внутренним сервисам запрещены.

Методы API

Загрузка контракта…

Страницы и фильтры списков

Для списков инвентаря передавайте limit=1..200, затем cursor из next_cursor, сохраняя остальные параметры. Без limit/cursor старые клиенты получают полный список: данные не обрезаются незаметно. Доступны status, member_id, user_id, vpn_id, search и created_from/created_to (RFC3339, нижняя граница включена, верхняя исключена). Доступ проверяется перед фильтрацией и на каждой странице. Неизвестные или повторные параметры — 422. Списки журнала активности используют отдельный контракт. Параметры каждого метода.

Что учитывает эта версия

Административный аудит хранится до 90 дней, максимум 10 000 последних событий на компанию; истёкшие записи идемпотентности очищаются. Счета и подписки эта очистка не удаляет. Списки инвентаря возвращают items, total и next_cursor; продолжение появляется при явном limit/cursor. Без них полный ответ совместим со старыми клиентами. Журнал activity отдельно поддерживает курсор и документированные фильтры. Секреты не повторяются в ответах из кеша идемпотентности. Подтверждённый отзыв ключа поступает от VPN-сервера; отключение членства сразу запрещает новую выдачу.

Мониторинг показывает фактические подключения и нагрузку. История направлений доступна через отдельный журнал с явным включением. Содержимое HTTPS и оценка продуктивности сотрудников в эти данные не входят. SSO/SCIM и другие методы из расширенного проекта не входят в этот реализованный контракт.

Ошибки управления возвращают application/problem+json с status, detail и request_id. Ошибки выдачи OAuth-токена используют поле error.