Выберите раздел в дереве слева.
CLI клиент
Описание
Общее описание функционала
CLI-клиент позволяет опубликовать локальный сервис по HTTP, HTTPS, TCP или UDP через туннель и получить для него публичный адрес. Он подходит для удалённого доступа, демонстраций и временного доступа к стенду. TCP и UDP требуют зарегистрированную учётную запись; бесплатного тарифа достаточно. Гостевой режим может применяться только к HTTP и HTTPS, если он разрешён на сервере. Для соединения используются WebSocket, QUIC или DTLS в зависимости от настроек и условий сети.
Как пользователь может использовать
- Разработчик публикует локальный веб-сервер и получает URL туннеля для быстрого доступа извне.
- Пользователь открывает доступ к локальной базе, сервису или тестовому стенду без отдельного проброса портов.
- Пользователь выбирает WebSocket, если сеть пропускает только обычные HTTPS-соединения.
- Пользователь переключается на QUIC или DTLS, когда нужен альтернативный транспорт для ограниченной сети.
- Пользователь настраивает TCP- или UDP-туннель для сервисов, которые не работают как обычный веб-сайт.
- Пользователь включает режим ожидания
stay, чтобы туннель оставался активным во время демонстрации или тестирования.
- Пользователь использует
watch, когда нужно отслеживать изменения состояния туннеля без ручного перезапуска.
- Пользователь передаёт секреты через флаги, файлы, стандартный ввод или переменные окружения, чтобы не хранить их в командной строке.
- Явные параметры командной строки (в том числе
-login и -pass) имеют приоритет над сохранённым в fortunnels.yml CLI-токеном.
- При исчерпании общего месячного трафика клиент показывает одно сообщение, прекращает передачу и завершает работу с ошибкой. Автоматическое переподключение и создание нового туннеля в этом состоянии не выполняются.
- Пользователь скачивает готовый бинарник со страницы загрузок продукта или ставит клиент через поддерживаемый пакетный менеджер.
Как это реализовано в сервисе
Пользователь запускает CLI с адресом локального сервиса и параметрами подключения. Клиент проходит аутентификацию или использует гостевой режим, создаёт туннель в сервисе и получает URL туннеля. Затем он открывает выбранный канал передачи данных и направляет через него внешний трафик к локальному сервису. Если режим работы не даёт отдельного сигнала о завершении, клиент периодически проверяет состояние туннеля и завершает работу, когда доступ больше не нужен или туннель больше не действует. Ошибки подключения, ограничений и недоступного транспорта выводятся в консоли понятным для пользователя сообщением.
Как использовать через CLI-клиент
Для HTTP, HTTPS и TCP можно передать только порт: например, fortunnels http 4321. В этом случае клиент обращается к localhost:4321, поэтому локальный сервис может слушать как IPv4, так и IPv6. Краткая форма UDP остаётся IPv4-вариантом: fortunnels udp 4321 использует 127.0.0.1:4321.
Если важна конкретная версия IP, укажите адрес полностью: host:port не меняется клиентом. Для сервиса, который доступен только по IPv6, можно сразу использовать ./bin/client http localhost:4321 или ./bin/client -protocol http -local '[::1]:4321'.
TCP и UDP запускайте с действующими учётными данными. Пароль безопаснее читать из стандартного ввода:
fortunnels tcp 5432 -login user@example.test -pass-stdin
fortunnels udp 9000 -login user@example.test -pass-stdin
Можно использовать действующий Bearer-токен через -token или -token-file. Если общий месячный лимит исчерпан, дождитесь следующего месяца по UTC или попросите администратора увеличить лимит. Перезапуск клиента, смена порта и пересоздание туннеля не обнуляют использование.
Для частного сервера с собственной доверенной CA укажите её PEM-файл только для QUIC или DTLS:
fortunnels udp 9000 -login user@example.test -pass-stdin -dp quic -transport-ca /path/to/ca.pem
Имя сервера и цепочка сертификата всё равно проверяются; этот флаг не отключает TLS-проверку и не добавляет CA в системное хранилище.
Справочник API
Создание туннеля (плоскость управления)
Клиент использует тот же REST API, что и дашборд: POST /api/tunnels с телом JSON (протокол, целевой адрес, опции авторизации туннеля и т.д.). Для TCP и UDP требуется заголовок Authorization: Bearer <token> или сессионная кука после входа. Бесплатного тарифа достаточно в пределах его лимитов.
Гостевое создание (если включено на сервере) относится только к HTTP и HTTPS: тот же маршрут без заголовка авторизации; в ответе — URL туннеля, срок жизни и лимиты.
Статус туннеля
GET /api/tunnels?id=<tunnel_id> — используется CLI для опроса жизненного цикла в режимах stay (HTTP/TCP expose-local/UDP), пока процесс удерживает туннель.
Удаление
DELETE /api/tunnels?id=<tunnel_id> — при поддержке сервером и политикой доступа.
Точные поля запроса и ответа совпадают с публичной справкой API сервера и типами в клиентском протоколе.
Транспорт данных
После создания туннеля клиент открывает WebSocket GET /ws (с параметрами режима и tunnel_id в строке запроса) или альтернативный транспорт (QUIC / DTLS) согласно флагам CLI и конфигурации сервера.
Ошибки
Ошибка аутентификации
Сообщение о неверном логине/пароле или просроченном токене; код выхода ненулевой. Нужно обновить учётные данные или получить новый токен.
Отказ в создании туннеля
Ответ API с телом JSON: поле error или message с человекочитаемым текстом (квота, запрещённый протокол, неверные параметры). Исправить параметры или тариф.
«Tunnel was removed. Exiting.»
Туннель удалён на сервере, истёк или доступ отозван; опрос GET /api/tunnels?id=... вернул признак отсутствия или 401. Запустить клиент заново и при необходимости создать новый туннель.
Ошибка сети / таймаут
Нет связи с сервисом ForTunnels. Проверить подключение к сети и DNS для fortunnels.ru.
«Backend unreachable» и недоступное локальное приложение
Сообщение появляется, когда клиент не может подключиться к локальному адресу туннеля. Если сервис открывается по localhost, но не открывается по 127.0.0.1, он, вероятно, слушает только IPv6. Для HTTP, HTTPS и TCP запустите туннель с localhost:<порт> или явно укажите [::1]:<порт>.
Туннель при этом остаётся активным. Публичный запрос может получить временный ответ 502, а следующий запрос снова проверит локальное приложение. После запуска или восстановления приложения перезапускать туннель не требуется.
Недостаточная длина PSK
При включённом шифровании потока PSK короче минимума — клиент завершится с ошибкой валидации до создания туннеля.
Ограничения
- CLI зависит от версии сервера: новые поля API могут требовать обновления клиента.
- Режим guest и лимиты гостевых туннелей задаются на сервере; пользователь не может продлить TTL или сбросить квоту из CLI.
- QUIC/DTLS могут быть недоступны, если сервер или сеть их блокирует; тогда используйте WebSocket.
- Опрос статуса в stay-режиме создаёт периодический трафик к API; при очень большом числе процессов учитывайте лимиты.
- Сообщения об ошибках в консоли не локализованы вне дашборда; язык зависит от версии клиента и ответов сервиса.
CLI-токен
Описание
Общее описание функционала
CLI-токен — персональный токен для подключения CLI-клиента ForTunnels к аккаунту пользователя. Он позволяет один раз настроить клиент на рабочей машине и дальше запускать туннели командами вроде fortunnels http 8080 без ручной передачи токена в каждом запуске.
CLI-токен создаётся в дашборде аккаунта на платном тарифе (функция CLI-токен в каталоге), показывается пользователю один раз и сохраняется локально в конфигурационный файл CLI. На бесплатном тарифе управление CLI-токенами в интерфейсе недоступно, а API отклоняет запросы с понятным кодом ограничения тарифа. Пользователь может видеть список активных CLI-токенов и отзывать те, которые больше не нужны.
Как пользователь может использовать
- Разработчик создаёт CLI-токен на своём ноутбуке и настраивает CLI один раз, чтобы быстро запускать HTTP-туннели к локальному приложению.
- Инженер использует отдельные CLI-токены для разных рабочих машин, чтобы при потере доступа к одной машине отозвать только её токен.
- Пользователь копирует готовую команду
fortunnels config add-authtoken ... из дашборда и не редактирует YAML вручную.
- Пользователь проверяет локальный файл конфигурации командой
fortunnels config check, прежде чем запускать туннель.
- Пользователь удаляет старый CLI-токен из дашборда, когда меняет устройство или больше не использует CLI на конкретной машине.
- Пользователь на бесплатном тарифе видит, что создание CLI-токена недоступно, и может перейти к смене тарифа из подсказки в интерфейсе.
- Пользователь на Pro или Enterprise создаёт и отзывает CLI-токены как обычно.
- Команда поддержки или администратор может попросить пользователя отозвать CLI-токен, если есть подозрение, что он был скомпрометирован.
- Пользователь хранит CLI-токен в стандартном для своей ОС месте: Linux, macOS и Windows используют разные пути, но CLI выбирает их автоматически.
Как это реализовано в сервисе
Пользователь создаёт CLI-токен в дашборде, сервис показывает секретное значение только в момент создания, а затем хранит у себя только безопасное представление токена. Когда CLI отправляет запрос на создание туннеля, сервис распознаёт персональный токен, связывает запрос с аккаунтом владельца и применяет обычные правила доступа, тарифов и блокировок.
Локальная команда конфигурации записывает CLI-токен в файл на машине пользователя. При запуске туннеля CLI читает этот файл, если токен не был передан более явным способом через флаг, файл секрета, stdin или переменную окружения.
Как использовать через CLI-клиент
После создания CLI-токена в дашборде сохраните его в локальной конфигурации клиента:
fortunnels config add-authtoken <ваш_токен>
Проверить, что файл конфигурации читается корректно:
fortunnels config check
Дальнейшие запуски туннелей (fortunnels http 8080, fortunnels tcp 22 и другие протоколы) подхватят токен автоматически; явная передача -token или переменной FORTUNNELS_TOKEN имеет более высокий приоритет. Подробнее — документация CLI-клиента.
Справочник API
Дашборд: управление токенами
Пользователь управляет CLI-токенами из дашборда. Эти маршруты требуют активной браузерной сессии. Для небезопасных методов используется защита CSRF, как и для других действий дашборда.
Получить список токенов
GET /api/me/authtokens
На бесплатном тарифе без возможности CLI-токен в плане: HTTP 403, JSON code: feature_disabled, feature_id: authtoken.
Успешный ответ:
{
"authtokens": [
{
"id": 1,
"name": "Laptop",
"prefix": "ft_abc123",
"created_at": "2026-05-31T21:00:00Z",
"last_used_at": "2026-05-31T21:10:00Z",
"expires_at": null
}
]
}
Полное значение токена в списке не возвращается.
Создать токен
POST /api/me/authtokens
На бесплатном тарифе без возможности CLI-токен в плане: HTTP 403, JSON code: feature_disabled, feature_id: authtoken, текст authtoken requires a paid plan.
Тело запроса:
{
"name": "Laptop",
"expires_at": "2026-12-31T00:00:00Z"
}
Поля name и expires_at необязательны.
Успешный ответ:
{
"id": 1,
"name": "Laptop",
"prefix": "ft_abc123",
"authtoken": "ft_..."
}
Поле authtoken показывается только один раз — в ответе на создание.
Отозвать токен
DELETE /api/me/authtokens/{id}
Успешный ответ: 204 No Content.
CLI: локальная конфигурация
CLI поддерживает команды:
fortunnels config add-authtoken YOUR_FORTUNNELS_TOKEN
fortunnels config check
config add-authtoken записывает токен в конфигурационный файл. config check проверяет наличие файла, корректность YAML, версию схемы и наличие agent.authtoken. Команда не обращается к серверу.
Формат файла:
version: 3
agent:
authtoken: YOUR_FORTUNNELS_TOKEN
Пути по умолчанию:
- Linux:
~/.config/fortunnels/fortunnels.yml
- macOS:
~/Library/Application Support/fortunnels/fortunnels.yml
- Windows:
%LOCALAPPDATA%\fortunnels\fortunnels.yml
Переменная FORTUNNELS_CONFIG задаёт пользовательский путь к конфигурационному файлу.
CLI: запуск туннеля
После настройки CLI использует CLI-токен из конфигурации при командах:
fortunnels http 8080
Более явные источники учётных данных имеют приоритет над конфигурационным файлом: флаг --token, затем --login с паролем (--pass, файл, stdin или FORTUNNELS_PASSWORD), затем --token-file, stdin и переменная FORTUNNELS_TOKEN. Сохранённый в fortunnels.yml CLI-токен используется только если выше ничего не задано.
Если одновременно указаны --login и токен в fortunnels.yml, клиент игнорирует файл и входит по логину и паролю; в stderr выводится предупреждение. Если используется только устаревший или недействительный токен из файла, клиент завершает работу с ошибкой (локально для просроченного JWT или после ответа сервера для недействительного ft_*) и подсказывает обновить или удалить agent.authtoken.
Ошибки
Ошибки дашборда
- HTTP
401: пользователь не вошёл в аккаунт или сессия истекла. Нужно войти в дашборд заново.
- HTTP
400: запрос на создание токена некорректен, например указан неверный формат expires_at. Нужно исправить данные и повторить действие.
- HTTP
403: действие заблокировано политикой доступа, CSRF-проверкой или ограничением тарифа. При code: feature_disabled и feature_id: authtoken сообщение указывает, что CLI-токен недоступен на текущем плане (authtoken requires a paid plan); нужно сменить тариф или обратиться к администратору.
- HTTP
404: пользователь пытается отозвать несуществующий токен или токен, который ему не принадлежит. Нужно обновить список токенов.
- HTTP
409: достигнут лимит активных токенов. Нужно отозвать старый токен и создать новый.
- HTTP
500: внутренняя ошибка сервиса. Нужно повторить позже или обратиться в поддержку.
Ошибки CLI-конфигурации
No configuration file at ...: файл конфигурации не найден. Нужно создать его вручную или выполнить fortunnels config add-authtoken <token>.
config version must be 3: версия схемы в YAML не поддерживается. Нужно указать version: 3.
agent.authtoken is required: в конфигурации нет токена. Нужно добавить agent.authtoken.
- Ошибка парсинга YAML: файл имеет некорректный синтаксис. Нужно исправить отступы и структуру YAML.
LOCALAPPDATA is not set на Windows: CLI не смог определить стандартный путь. Нужно задать LOCALAPPDATA или FORTUNNELS_CONFIG.
Ошибки запуска туннеля с CLI-токеном
- HTTP
401 при создании туннеля: токен неверный, отозван, истёк или не принят сервером. Нужно создать новый токен в дашборде и обновить локальную конфигурацию.
- HTTP
403 при создании туннеля: аккаунт заблокирован или действие запрещено тарифом/политикой доступа. Нужно проверить статус аккаунта и ограничения тарифа.
- Сообщение о недоступном сервере: CLI не смог подключиться к серверу ForTunnels. Нужно проверить сеть и DNS для
fortunnels.ru.
Ограничения
Одноразовый показ токена
Полное значение CLI-токена показывается только сразу после создания. Если пользователь закрыл окно или не сохранил токен, нужно создать новый токен и отозвать старый.
Локальная проверка конфигурации
fortunnels config check проверяет только локальный файл: путь, YAML, версию схемы и наличие agent.authtoken. Команда не подтверждает, что токен действителен на сервере.
Ручная защита локального файла
CLI записывает конфигурационный файл с ограниченными правами, но пользователь отвечает за безопасность своей машины, резервных копий и синхронизаций домашней директории.
Лимит активных токенов
У аккаунта есть ограничение на количество активных токенов. Если лимит достигнут, нужно отозвать неиспользуемые токены.
Тарифный план
Функция CLI-токен доступна только когда она включена в активный тариф пользователя (по умолчанию — платные планы Pro и Enterprise). На Free дашборд не загружает список токенов и блокирует создание и отзыв; прямые запросы к API управления токенами возвращают отказ с кодом feature_disabled.
Приоритет источников токена
Если пользователь одновременно указал токен через флаг, переменную окружения и конфигурационный файл, CLI выберет более явный источник. Это может выглядеть так, будто конфигурационный файл игнорируется.
Отзыв не завершает уже запущенный процесс мгновенно
Отзыв токена запрещает будущую аутентификацию этим токеном. Уже созданный туннель может завершиться по обычным правилам жизненного цикла соединения и серверных проверок.
HTTP/HTTPS туннели
Описание
Общее описание функционала
Функциональность отвечает за публичный доступ к вашим HTTP- и HTTPS-приложениям через туннель: внешний клиент обращается к поддомену URL туннеля на домене сервиса (например label.fortunnels.ru), а запрос перенаправляется на целевой хост и порт, который вы указали при создании туннеля. Для одноуровневого поддомена URL туннеля на домене сервиса для туннелей зарегистрированных пользователей нужен владелец, администратор или гостевой туннель; сессия или токен должны позволять сервису определить пользователя (cookie сессии на родительском домене или Authorization: Bearer). Для привязанного пользовательского домена по-прежнему допускается публичный доступ по знанию имени хоста — без проверки владения сессией, как «ссылка-возможность»; после этого по-прежнему применяются списки доступа по IP, лимиты и тариф. Проверка владельца, гостевого режима и администратора для поддомена на домене сервиса выполняется до списков доступа по IP и лимитов. Сервис проверяет, существует ли туннель и разрешён ли запрос. Дополнительно могут применяться ограничения по IP, частоте запросов и условиям тарифа (квоты и включённые возможности). При недоступности целевого приложения или срабатывании ограничений клиент получает понятный по смыслу ответ об ошибке вместо успешного ответа от вашего приложения.
Если обязательный скрипт, стиль, сетевое соединение или другой критичный ресурс заблокирован политикой Content Security Policy (CSP) самого приложения, Fortunnels может показать в этом браузере отдельную страницу с объяснением. Политика приложения при этом остаётся неизменной: исправлять её нужно в самом приложении.
Как пользователь может использовать
- Разработчик поднимает API или веб-интерфейс локально и открывает его коллегам или тестовой среде по выданному URL туннеля, не выставляя машину в интернет напрямую.
- Интегратор проверяет вебхуки или OAuth-редиректы: внешний сервис шлёт запросы на адрес туннеля, а трафик доходит до локального стенда.
- Владелец туннеля делится URL туннеля на поддомене сервиса с коллегами и интеграциями.
- Владелец на платном тарифе в дашборде туннелей переключает колонку «Публичный», чтобы скрыть HTTP/HTTPS-туннель от анонимных посетителей или снова открыть его; подробнее — приватные HTTP-туннели.
- Для приложений на Next.js и похожих SPA URL туннеля на поддомене обычно работает прозрачно для типовых запросов, включая загрузку
_next-ресурсов, fetch, WebSocket, EventSource и sendBeacon.
- Пользователь с гостевым туннелем (доступный всем) демонстрирует прототип заказчикам без входа в аккаунт у них; при этом приватные туннели остаются доступны только владельцу и уполномоченным ролям.
- Администратор в личном кабинете (
/dashboard/tunnels) видит в списке только свои туннели; полный обзор всех пользователей — в админ-консоли на выделенном админ-хосте. Отладка чужого туннеля через Inspector по прямой ссылке из админ-консоли по-прежнему доступна.
- Клиент API или скрипт автоматизации дергает те же URL туннелей, что и браузер, для проверки поведения за прокси (заголовки, редиректы, тело ответа).
- Разработчик видит пустую или неполную страницу из-за CSP, перезагружает её после отправки отчёта браузером и получает понятную диагностику. После исправления политики кнопка Try again возвращает его на тот же адрес туннеля.
- Пользователь сталкивается с временной приостановкой туннеля и видит, что сервис недоступен до возобновления, вместо устаревшего ответа.
- Владелец плана с лимитами отслеживает, что при исчерпании квоты или отключённой возможности запросы к туннелю отклоняются с явным сигналом, а не проксируются «в никуда».
- Пользователь с ограничениями по IP или частоте запросов понимает по ответу сервиса, что доступ временно или постоянно ограничён политикой безопасности или защитой от злоупотреблений.
- Посетитель основного сайта сервиса и посетитель URL туннеля получают согласованное поведение по протоколу (например, ожидаемые редиректы на HTTPS там, где это задумано продуктом).
- Поддерживаются долгоживущие соединения WebSocket через тот же обратный прокси, при условии корректных таймаутов на публичном входе.
- Если приложение критически зависит от service worker, офлайн-кэша или фонового перехвата запросов, убедитесь, что оно корректно обслуживается с корневого пути на выданном публичном хосте.
- Нужны формализованные истории уровня продукта — см. пользовательские истории HTTP/HTTPS.
Как это реализовано в сервисе
Входящий HTTP-запрос сначала попадает на публичную точку входа: по заголовку Host определяется, к какому туннелю относится запрос; затем проверяется, что туннель существует и находится в состоянии, допускающем обработку. Для одноуровневого поддомена на домене сервиса (URL туннеля вида label.<домен_сервиса>) для туннелей с владельцем выполняется проверка доступа (владелец, гость, администратор) до списков доступа по IP. Для хоста, привязанного как пользовательский домен, публичный доступ по знанию имени хоста сохраняется; затем по-прежнему применяются списки доступа по IP, лимиты и тарифные проверки владельца. В API списков и чтения туннелей для гостей может использоваться скрытие факта существования чужих туннелей (404), что не отменяет описанную модель прокси. После этого учитываются сетевые списки доступа, ограничение интенсивности запросов и условия тарифа владельца. Если все проверки пройдены, сервис пересылает запрос на целевой адрес туннеля и возвращает ответ приложения. При ошибке маршрутизации, доступа, лимита, подключения или тайм-ауте ответ формирует Fortunnels.
Для CSP-диагностики сервис добавляет к подходящему HTML-ответу отдельную политику только для отчётов и не меняет политику, которую применяет браузер. После критичного нарушения браузер асинхронно отправляет отчёт. Следующая перезагрузка или переход верхнего уровня в том же браузере может получить диагностическую страницу. Другие браузеры продолжают получать исходный ответ приложения, даже если его CSP мешает отображению; запросы к API, ресурсам и WebSocket также не заменяются этой страницей.
Как использовать через CLI-клиент
HTTP- или HTTPS-туннель запускается из CLI с указанием локального адреса приложения. Краткая форма — порт как позиционный аргумент; для неё клиент использует localhost:<порт>. Явный адрес через -local сохраняется без изменений.
Пример для локального веб-сервера на порту 8080:
fortunnels http 8080
или:
fortunnels -protocol http -local 127.0.0.1:8080
Если приложение слушает только IPv6, подойдут ./bin/client http localhost:4321 или ./bin/client -protocol http -local '[::1]:4321'.
После успешного создания клиент выводит URL туннеля; процесс остаётся активным, пока вы его не остановите. Для доступа от имени аккаунта передайте токен (-token), логин и пароль (-login) или заранее сохраните CLI-токен (fortunnels config add-authtoken …). Режим отслеживания состояния туннеля — флаг -watch. Полный перечень флагов транспорта и протоколов — в документации CLI-клиента.
Справочник API
Публичное проксирование
GET https://{subdomain}.{domain}/* — проксирование HTTP-запросов к целевому туннелю по поддомену из URL туннеля (в ответе API — поле public_url)
GET https://{custom_domain}/* — маршрутизация по привязанному пользовательскому домену
Поддерживаются все HTTP-методы (GET, POST, PUT, DELETE и др.). Заголовки, тело и параметры запроса сохраняются при пересылке.
Управление туннелями (API)
POST /api/tunnels — создание туннеля с протоколом HTTP/HTTPS
GET /api/tunnels?id=<id> — получение информации о туннеле (или GET /api/tunnels со списком)
PATCH /api/tunnels — обновление конфигурации туннеля; в теле JSON укажите id и действие (пауза, транспорт, TLS, регенерация URL, редиректы и т.д.)
DELETE /api/tunnels?id=<id> — удаление туннеля
Для HTTP/HTTPS-туннелей поддерживается действие set_public_subdomain: в теле JSON указываются id, action: "set_public_subdomain" и поле public_subdomain (метка поддомена). Ограничения: валидация метки, уникальность хоста, зарезервированные имена, при включённых тарифах — возможность custom-public-subdomain, отдельный лимит частоты смены метки, максимальный размер тела PATCH. Коды ответов: см. раздел Ошибки возможности «Свой поддомен» в документации.
Для зарегистрированных пользователей с тарифными планами при создании туннеля возможны ответы 403 с JSON-кодами: user_suspended (аккаунт заблокирован) или quota_exceeded с полем quota: max_concurrent_tunnels (превышен лимит одновременных туннелей). Поле expires_at в ответе может отражать ограничение срока жизни туннеля по плану.
Запрос создания туннеля
{
"protocol": "http",
"target_addr": "127.0.0.1:8000"
}
Владелец определяется сессией или Bearer-токеном; идентификатор владельца не передаётся клиентом в теле запроса.
Ответ создания туннеля
{
"id": "a1b2c3d4e5f6g7h8",
"protocol": "http",
"target_addr": "127.0.0.1:8000",
"public_url": "http://xyz789.fortunnels.ru",
"created_at": "2024-01-01T12:00:00Z",
"expires_at": "2024-01-01T14:00:00Z"
}
Поддомен URL туннеля генерируется независимо от id туннеля для повышения безопасности (в ответе API — поле public_url).
Список и детали туннеля (GET /api/tunnels, GET /api/tunnels?id=<id>)
Ответ списка и одиночного туннеля включает поля created_at, expires_at, bytes_used, traffic_limit_bytes и объект limit_indicators — компактные индикаторы лимитов для интерфейса (без отдельного запроса на строку).
limit_indicators
| Поле | Описание |
|------|----------|
| as_of | Момент расчёта на сервере (RFC3339) |
| lifetime | Оставшееся время жизни туннеля из created_at / expires_at |
| traffic | Per-tunnel трафик из bytes_used / traffic_limit_bytes (для гостевых туннелей); для зарегистрированных владельцев — unavailable (месячный egress аккаунта не показывается как per-tunnel cap) |
| http_rpm | Оставшаяся ёмкость HTTP-запросов в минуту по плану в текущем окне |
Состояния каждого индикатора: limited, unlimited, unavailable, zero_limit, exhausted, expired.
Снимок http_rpm носит информационный характер и не расходует лимит запросов при чтении; фактическое ограничение применяется при обработке HTTP-запросов к туннелю.
Для не-админов поля user_id и owner_login по-прежнему опускаются в теле туннеля; limit_indicators не содержит owner/account/plan идентификаторов.
Область списка для администратора
Один и тот же endpoint GET /api/tunnels возвращает разный набор туннелей в зависимости от того, откуда администратор открыл интерфейс:
| Контекст | Где в продукте | Что в списке |
|----------|----------------|--------------|
| Личный кабинет | /dashboard/tunnels на основном домене | Только туннели, принадлежащие этому администратору (как у обычного пользователя) |
| Админ-консоль | /tunnels на выделенном админ-хосте (например admin.fortunnels.ru; в локальной разработке — /admin/tunnels) | Все туннели всех пользователей |
В личном кабинете администратор не видит чужие туннели в списке, счётчиках и пагинации. В админ-консоли по-прежнему доступен полный обзор флота; в списке для чужих туннелей могут отображаться поля владельца (owner_login, user_id).
Исключение: открытие конкретного туннеля или Inspector по прямой ссылке (в том числе переход из админ-консоли на /dashboard/tunnels/{id}/inspector для чужого туннеля) по-прежнему разрешено администратору — это не расширяет список в личном кабинете.
CLI и прочие API-клиенты без контекста админ-консоли получают лично-кабинетный список (только свои туннели).
Пример фрагмента:
{
"limit_indicators": {
"as_of": "2026-06-05T12:00:00Z",
"lifetime": {
"state": "limited",
"used_seconds": 120,
"remaining_seconds": 480,
"total_seconds": 600,
"reset_at": "2026-06-05T14:00:00Z"
},
"traffic": {
"state": "limited",
"used_bytes": 256,
"remaining_bytes": 768,
"total_bytes": 1024
},
"http_rpm": {
"state": "limited",
"used_requests": 3,
"remaining_requests": 7,
"total_requests": 10,
"reset_at": "2026-06-05T12:01:00Z"
}
}
}
Поле remaining_requests в http_rpm — оставшаяся ёмкость HTTP requests/min в текущем окне (не current_http_requests_per_minute).
Ошибки
413 Payload Too Large
Когда возникает: Тело запроса PATCH /api/tunnels/{id} превышает лимит размера (внутренний порог для JSON-действий с туннелем).
Что делать: Уменьшить тело запроса; для set_public_subdomain достаточно компактного JSON с полями id, action, public_subdomain.
400 Bad Request
Когда возникает: Невалидный формат ID туннеля, некорректный запрос, попытки path traversal (../ в путях), невалидная метка public_subdomain, зарезервированное имя поддомена, действие только для HTTP/HTTPS.
Что делать: Проверить корректность URL и ID туннеля. Убедиться, что путь не содержит недопустимых последовательностей.
403 Forbidden
Когда возникает: ACL запретил доступ, требуется аутентификация, пользователь обращается к чужому туннелю.
Что делать: Проверить права доступа и настройки ACL туннеля. Убедиться, что аутентификация валидна и пользователь имеет право доступа к туннелю.
404 Not Found
Когда возникает: Туннель не найден, невалидный путь или ID туннеля.
Что делать: Проверить корректность ID туннеля и URL. Убедиться, что туннель существует и не истёк.
429 Too Many Requests
Когда возникает: Превышен лимит запросов (глобальный, на пользователя или на туннель).
Что делать: Снизить частоту запросов. Заголовок Retry-After указывает, когда можно повторить запрос.
502 Bad Gateway
Когда возникает: Целевой сервис недоступен, подключение не удалось или истёк таймаут. Сообщение connection refused часто означает, что адрес выбран не для той версии IP: приложение может слушать ::1, но не 127.0.0.1. Ещё один случай — диагностическая страница после того, как этот браузер сообщил о критичном нарушении CSP приложения.
Что делать: Убедиться, что локальный сервис запущен и доступен по адресу туннеля. Сравните:
curl -I http://localhost:<порт>/
curl -I http://127.0.0.1:<порт>/
Если первый запрос успешен, а второй нет, создайте HTTP-, HTTPS- или TCP-туннель с localhost:<порт> либо явно укажите [::1]:<порт>. Туннель остаётся активным; ответ 502 временный, и следующий публичный запрос повторит подключение после восстановления приложения.
Если на странице указана CSP-ошибка, проверьте названную директиву и разрешённый источник в настройках самого приложения. Затем нажмите Try again. Кнопка сбрасывает отметку только для текущего браузера и возвращает на тот же адрес туннеля. Если политика исправлена, приложение загрузится; Fortunnels не отключает и не ослабляет CSP. Другой браузер эта отметка не затрагивает.
503 Service Unavailable
Когда возникает: Туннель приостановлен; туннель возобновлён в панели, но клиент ещё не переподключился («Туннель возобновляется»); или временные проблемы на стороне сервера.
Что делать: Проверить статус туннеля через API. Если туннель возобновлён — подождать несколько секунд (клиент переподключается после паузы). Возобновить туннель при необходимости.
504 Gateway Timeout
Когда возникает: Превышен таймаут запроса к целевому сервису.
Что делать: Проверить доступность и нагрузку локального сервиса. Увеличить таймаут в конфигурации туннеля при необходимости.
Ограничения
- Доступность туннеля зависит от состояния локального приложения и сетевого соединения клиента.
- Долгоживущие WebSocket-соединения зависят от таймаутов клиента, сервиса и целевого приложения.
- Приложения, которые жёстко ожидают корневой путь исходного домена или используют service worker, могут требовать отдельной настройки; для таких случаев предпочтительнее отдельный публичный хост.
- Ограничения тарифа, частоты запросов, размера запроса и IP-доступа применяются до передачи запроса в локальное приложение.
- CSP-диагностика работает по принципу «сначала отчёт, затем перезагрузка». Отчёт отправляется асинхронно, поэтому первый показ страницы может остаться пустым или неполным. Диагностика появляется при следующей перезагрузке или другом переходе верхнего уровня в том же браузере.
- В текущей версии учитывается только применяемая браузером CSP из заголовка ответа подходящей HTML-страницы. Политика, заданная только через HTML-метатег, и отдельная политика только для отчётов сами по себе не включают диагностику.
- Диагностическая страница предназначена только для переходов верхнего уровня. Фреймы, скачивания, перенаправления, API-запросы, ресурсы страницы и WebSocket-соединения продолжают обрабатываться как обычно.
- Диагностика поддерживает директивы скриптов
script-src, script-src-elem и script-src-attr; стилей style-src, style-src-elem и style-src-attr; соединений connect-src; фоновых процессов worker-src; а также require-trusted-types-for и trusted-types. Резервная директива child-src учитывается только тогда, когда браузер связывает нарушение с worker-src. Другие нарушения, например блокировка необязательного изображения или шрифта, не включают диагностическую страницу.
- Состояние диагностики хранится только в браузере, который отправил отчёт. Оно не отключает туннель для остальных посетителей и не меняет CSP приложения.
Пауза туннеля
Общее описание функционала
Пауза HTTP-туннеля временно закрывает публичный доступ, не удаляя сам туннель и его адрес. Уже запущенный клиент может автоматически переподключаться и отправлять сигналы активности, но запросы всё равно не проходят, пока владелец не возобновит туннель. После возобновления тот же туннель может снова принимать запросы без перезапуска клиента.
Как пользователь может использовать
- Разработчик ставит туннель на паузу на ночь, чтобы временно закрыть доступ к локальному сервису.
- Владелец оставляет клиент запущенным во время паузы и возобновляет тот же туннель, когда доступ снова нужен.
- Пользователь видит в дашборде статус «Приостановлен» и понимает, что публичный вход намеренно отключён.
- Команда прерывает долгий HTTP-запрос паузой и знает, что сервис не повторит его автоматически после возобновления.
- Администратор приостанавливает туннель пользователя при инциденте.
- После возобновления пользователь повторяет запрос; если связь с клиентом ещё восстанавливается, сервис временно сообщает об ожидании переподключения.
- Владелец управляет паузой при наличии нужных прав и функции в тарифе; администратор сохраняет отдельные административные полномочия.
Как это реализовано в сервисе
Команда паузы сохраняет состояние «Приостановлен», прекращает передачу публичных HTTP-запросов и завершает запросы, которые уже выполнялись. Переподключения и сигналы активности клиента не отменяют паузу. Команда возобновления возвращает прежний публичный адрес в работу. Если соединение клиента готово, новые запросы сразу идут к локальному сервису; если нет, сервис до 60 секунд отвечает сообщением о переподключении, а затем обычным ответом о временной недоступности. Проверки прав и тарифа для паузы и возобновления остаются теми же.
Пауза и возобновление
PATCH /api/tunnels
Тело JSON включает идентификатор туннеля и поле действия:
action: pause — приостановить туннель.
action: resume — возобновить туннель.
Успех: ответ с обновлённым объектом туннеля (в т.ч. поле статуса paused / active) в формате вашего API.
Права: владелец туннеля или администратор.
Связанное действие
action: regenerate_url — для TCP в активном состоянии перевыделяет публичный порт; для приостановленного TCP может возвращаться ошибка с просьбой сначала выполнить resume (сообщение в теле ответа).
400 Bad Request
Недопустимое действие для текущего состояния (например, regenerate_url для TCP на паузе) — в теле JSON текст с подсказкой сначала resume.
401 / 403
Нет прав изменять туннель.
503 Service Unavailable (HTTP после resume)
Кратковременно после возобновления, пока клиент данных не переподключился — вместо прокси к цели может отдаваться ответ о ожидании переподключения в пределах настроенного окна.
Ограничения
- На паузе HTTP-туннель возвращает
503 Service Unavailable, в том числе после автоматического переподключения клиента и его сигналов активности.
- HTTP-запрос, который выполнялся в момент паузы, завершается. Сервис не сохраняет его данные и не повторяет запрос после возобновления.
- Если соединение клиента ещё не готово, после возобновления сервис может до 60 секунд показывать сообщение о переподключении. Затем он возвращает обычный ответ
503 Service Unavailable, пока связь не восстановится.
- Истёкший или закрытый туннель нельзя возобновить; вместо него нужно создать новый.
Свой поддомен
Общее описание функционала
Функция «Свой поддомен» позволяет владельцу HTTP/HTTPS-туннеля задать стабильную метку в адресе вида https://{метка}.{домен_сервиса}/… вместо случайного поддомена, чтобы делиться одной и той же ссылкой с командой и интеграциями. Метка должна быть корректной DNS-меткой, не входить в зарезервированный список и быть уникальной в системе. На тарифах без этой возможности панель и API возвращают отказ с указанием функции; администраторы при управлении чужими туннелями ограничения тарифа обычно не испытывают.
Как пользователь может использовать
- Разработчик после создания туннеля в дашборде задаёт свой поддомен в карточке туннеля или через API PATCH с действием
set_public_subdomain.
- Пользователь делится коротким брендированным URL с заказчиком на поддомене домена сервиса. Каноническая ссылка для HTTP/HTTPS — URL туннеля вида
https://{метка}.{домен_сервиса}/….
- Интегратор настраивает OAuth redirect URI на постоянный хост туннеля.
- Владелец переименовывает поддомен в пределах правил уникальности (старое имя освобождается для других после успешного перехода).
- Пользователь на бесплатном плане пытается включить метку и получает понятный отказ с предложением сменить тариф.
- Администратор правит поддомен для туннеля пользователя при операционной необходимости.
Как это реализовано в сервисе
Запрос на смену метки приходит на плоскость управления вместе с идентификатором туннеля. Сервер проверяет владельца (или администратора), правила тарифа для обычных пользователей, формат метки, уникальность и частоту смены (защита от злоупотреблений). После успеха обновляется запись туннеля с новым URL туннеля и обновляется соответствие имя хоста → туннель, чтобы входящие запросы по новому имени сразу попадали в тот же туннель. Дальнейшая обработка запроса совпадает с обычной HTTP-маршрутизацией: проверки доступа, лимиты и обратный прокси к локальному сервису.
Смена своего поддомена
PATCH /api/tunnels (тот же маршрут, что и для других действий над туннелем).
Тело JSON (поля уточняйте по актуальному контракту API создания/изменения туннеля):
id — идентификатор туннеля (должен совпадать с объектом изменения).
action: set_public_subdomain
public_subdomain: строка — метка поддомена (только допустимые символы DNS-метки, без точек).
Успех: туннель возвращается с обновлённым URL туннеля (в ответе API — поле public_url) и полями хоста (как в ответе вашего API PATCH).
Ошибки: 400 (неверная метка, зарезервировано, не HTTP(S) туннель), 403 (нет функции в тарифе для не-админа), 409 (метка занята), 429 (слишком частые переименования), 413 (слишком большое тело запроса).
Авторизация
Требуется вход в дашборд или Bearer-токен. Не-владелец (кроме администратора) не может менять чужой туннель.
400 Bad Request
Недопустимая метка (длина, символы, дефисы), метка в зарезервированном списке, или туннель не HTTP/HTTPS — в теле JSON указано сообщение об ошибке.
401 Unauthorized
Пользователь не аутентифицирован.
403 Forbidden
Нет прав на изменение туннеля или у пользователя нет функции custom-public-subdomain в тарифе (код вроде feature_disabled в JSON).
409 Conflict
Такой поддомен уже используется другим туннелем.
413 Payload Too Large
Тело PATCH превышает лимит сервера.
429 Too Many Requests
Превышен лимит частоты переименований поддомена для пользователя.
Ограничения
- Доступно только для туннелей с протоколом HTTP или HTTPS.
- Метка — одна DNS-метка без точек; полноценный произвольный домен — отдельная возможность продукта (кастомные домены).
- Смена поддомена ограничена по частоте на пользователя.
- Уникальность проверяется глобально в пределах окружения: занятая метка недоступна другому туннелю, пока не освобождена.
Приватные HTTP-туннели
Общее описание функционала
Приватные HTTP-туннели позволяют владельцу скрыть туннель от анонимного доступа по URL туннеля. Пока туннель помечен как приватный, входящие запросы без действующего токена доступа (ссылка-приглашение или cookie после перехода по такой ссылке) получают отказ. В публичном режиме (по умолчанию) любой, кто знает URL туннеля, может обратиться к нему с учётом общих ограничений сервиса (лимиты, списки IP и тариф). Владелец может вернуть туннель в публичный режим; при этом все ранее выданные ссылки доступа отзываются. Функция доступна только для протоколов HTTP/HTTPS и на тарифах с правом приватных туннелей.
Панель управления
В личном кабинете на странице Туннели у каждого активного HTTP- или HTTPS-туннеля отображается колонка «Публичный» с переключателем:
| Положение | Режим | Кто может открыть URL туннеля |
|-----------|--------|-------------------------------|
| Включено | Публичный (по умолчанию) | Любой посетитель по известному URL (с учётом лимитов и политик доступа) |
| Выключено | Приватный | Владелец, администратор и гости с действующей ссылкой доступа; анонимные запросы отклоняются |
Тариф: перевести туннель из публичного в приватный могут пользователи с правом «приватные туннели» на платном тарифе. На бесплатном тарифе переключатель в положении «публичный» заблокирован; при наведении показывается подсказка со ссылкой на смену тарифа. Вернуть приватный туннель в публичный режим можно на любом тарифе.
Подтверждение: при переключении приватный → публичный сервис запрашивает подтверждение, потому что все активные ссылки доступа будут отозваны. Переход публичный → приватный выполняется сразу, без дополнительного диалога.
Тот же переключатель доступен в админ-консоли в списке всех туннелей.
Как пользователь может использовать
- Разработчик на платном тарифе создаёт HTTP-туннель и в дашборде выключает «Публичный», чтобы случайные посетители не видели локальный сервис.
- Владелец выдаёт коллеге ссылку доступа через API (см. справочник API) и отзывает её после демо.
- Пользователь возвращает туннель в публичный режим для открытого тестирования — после подтверждения в дашборде.
- Пользователь на бесплатном тарифе видит заблокированный переключатель и подсказку о смене тарифа; при создании туннель остаётся публичным.
Как это реализовано в сервисе
При создании или изменении туннеля сервер применяет эффективную видимость: без права на тарифе запрос на приватность принудительно переводит туннель в публичный режим. Команда смены видимости через API или переключатель в дашборде меняет флаг публичности; переход в приватный режим проверяет тариф. Прокси для приватного туннеля проверяет токен в параметре запроса, заголовке или cookie. Ссылки создаются и отзываются через API. При смене тарифа без права сервер синхронизирует приватные туннели в публичные и очищает токены.
API (приватные туннели)
Смена видимости
Через дашборд: колонка «Публичный» на странице Туннели (то же в админ-консоли). Переключатель вызывает ту же операцию, что и API ниже.
PATCH /api/tunnels с телом:
{
"id": "<tunnel_id>",
"action": "set_visibility",
"is_public": false
}
is_public: false — сделать туннель приватным (только HTTP/HTTPS).
is_public: true — вернуть публичный режим; все share-токены отзываются.
Требуется аутентификация владельца или администратора. На тарифе без private-tunnels — 403 с code: feature_disabled.
Ссылки доступа
GET /api/tunnels/{id}/share-links — список активных ссылок (только владелец).
POST /api/tunnels/{id}/share-links — создать ссылку (тело: label, опционально expires_at).
DELETE /api/tunnels/{id}/share-links/{token_id} — отозвать ссылку.
Создание ссылок разрешено только для приватных HTTP/HTTPS туннелей.
Доступ гостя
Гость открывает URL с параметром токена или проходит bootstrap; сервис выставляет cookie доступа до истечения срока ссылки.
Ошибки (приватные туннели)
| Ситуация | HTTP | Сообщение / код |
|----------|------|-----------------|
| Тариф без приватных туннелей (PATCH set_visibility → private) | 403 | feature_disabled, feature_id: private-tunnels |
| Приватность для TCP/UDP | 400 | private visibility requires http or https tunnel |
| Создание share-link для публичного туннеля | 400 | share links only for private tunnels |
| Анонимный доступ к приватному туннелю | 403 | forbidden (без валидного токена) |
| Просроченный или отозванный токен | 403 | forbidden |
При понижении тарифа приватные туннели автоматически переводятся в публичный режим без отдельного запроса пользователя.
Известные ограничения
- Приватный режим поддерживается только для HTTP и HTTPS; TCP-туннели всегда публичны по политике сервиса.
- Переключатель «Публичный» в дашборде показывается только для активных HTTP/HTTPS-туннелей; для туннелей на паузе или неактивных колонка пуста.
- На тарифе без права приватных туннелей новый туннель при создании остаётся публичным; переключатель в дашборде не позволяет сделать его приватным.
- Переход в публичный режим безвозвратно отзывает все активные ссылки доступа для туннеля.
- Управление ссылками доступа (создание и отзыв) в дашборде не предусмотрено — только через API; в интерфейсе доступна смена режима публичный/приватный.
Manual webhook test events
Описание
Общее описание функционала
Ручные тестовые вебхуки позволяют отправить HTTP-запрос на ваш HTTP/HTTPS-туннель или облачный webhook inbox прямо из инспектора HTTP-трафика, без вызова из внешнего провайдера. Запрос всегда идёт только на текущую цель выбранного эндпоинта — абсолютные URL и сторонние хосты недоступны.
Вы можете собрать запрос вручную, выбрать встроенный пример, сохранить шаблон для повторного запуска или создать шаблон из уже зафиксированного события инспектора с маскировкой чувствительных полей. Каждая успешная отправка или запуск шаблона создаёт новое событие в инспекторе с тегом webhook-test-event, чтобы результат сразу открыть в деталях.
Функция доступна на тарифах с возможностью webhook-test-events (как правило, на оплачиваемых планах). Панель тестирования отображается только на странице HTTP-инспектора HTTP/HTTPS-туннеля или inbox, не на TCP/UDP-инспекторах.
В первой версии библиотека шаблонов личная: шаблоны принадлежат вашему аккаунту и одному эндпоинту (tunnel_id). Общие библиотеки команды, сред или организации пока недоступны. Шаблоны и события других пользователей через API не видны — запрос возвращает отказ «не найдено».
Как пользователь может использовать
- Разработчик проверяет обработчик вебхука на локальном сервисе: подключает клиент туннеля, открывает инспектор, отправляет POST с JSON и сравнивает код ответа downstream с ожиданием.
- Интегратор тестирует webhook inbox в режиме «только хранение»: отправляет ручной запрос и убеждается, что событие сохранено в инспекторе без доставки на локальный сервис.
- QA воспроизводит сценарий с query-параметрами и заголовками, сохраняет шаблон «успешный платёж» и запускает его перед каждым релизом.
- Пользователь находит неудачный входящий вебхук в инспекторе, нажимает «Сохранить как шаблон», получает очищенную копию с перечислением замаскированных полей и правит шаблон перед повторными прогонами.
- Разработчик выбирает встроенный пример «Invalid JSON» или «Missing field JSON», отправляет его на staging через туннель и проверяет валидацию на бэкенде.
- Команда документирует ожидаемый исход сценария через поле «пример результата» (
success, failure, unspecified) и теги в библиотеке шаблонов.
- Пользователь с несколькими эндпоинтами держит отдельные библиотеки шаблонов: каждый шаблон принадлежит одному
tunnel_id и не переносится на другой URL автоматически.
- После исправления кода пользователь запускает сохранённый шаблон кнопкой Run и сразу видит новое событие в деталях инспектора — без ручного поиска в списке.
- Пользователь сравняет ручную отправку с повтором запроса (Replay): replay воспроизводит уже зафиксированное событие, а ручной тест создаёт новый синтетический запрос с нуля или из шаблона.
- Разработчик через REST API автоматизирует прогон набора шаблонов в CI, используя
POST /api/webhook-test-events/templates/<id>/run с сессией дашборда или токеном.
- Пользователь на тарифе без функции видит скрытую или неактивную панель; при попытке вызова API получает отказ с объяснением по тарифу (см. ошибки).
- Оператор поддержки просит клиента отправить тест из инспектора конкретного inbox и проверяет
event_id в ответе панели, чтобы сопоставить с записью в журнале.
- Пользователь готовит библиотеку шаблонов, пока клиент туннеля ещё не подключён: сохраняет запросы на своём эндпоинте и запускает их после появления доставки.
- Пользователь переключается между вкладками Тест, События и Настройки в инспекторе, не теряя несохранённые поля ручного запроса на вкладке Тест.
- Пользователь редактирует поля вручную и выбирает встроенный пример — интерфейс спрашивает подтверждение, прежде чем заменить уже изменённый запрос.
- Владелец webhook inbox открывает инспектор эндпоинта, а настройки inbox (режим доставки, состояние) переходит через пункт Webhook inbox в боковом меню дашборда.
Как это реализовано в сервисе
1. Вы открываете /dashboard/tunnels/<tunnel_id>/inspector для HTTP/HTTPS-туннеля или webhook inbox. Для HTTP-эндпоинтов инспектор разделён на вкладки Тест, События и Настройки; блок ручного тестирования находится на Тест. Несохранённый запрос остаётся в форме при переключении вкладок. Если тариф и тип эндпоинта позволяют, панель тестирования доступна для отправки и шаблонов.
2. Запрос (ручной, из встроенного примера или из сохранённого шаблона) проходит проверку входа, доступа к эндпоинту, лимита частоты HTTP-запросов и ограничения размера тела (32 КБ). Чувствительные заголовки и поля в query/JSON маскируются до сохранения шаблона или доставки.
3. Сервис определяет текущую цель эндпоинта (локальный адрес туннеля, режим inbox или пересылка) и отправляет запрос только через этот канал — без подстановки адреса из шаблона, если эндпоинт уже изменён или удалён.
4. Для inbox в режиме «только хранение» или при недоступной доставке создаётся синтетическое событие с ответом «сохранено»; для активного туннеля с подключённым клиентом фиксируются реальный код и тело ответа downstream.
5. Событие записывается в инспектор синхронно: API возвращает event_id только после того, как записи доступны через GET /api/v1/inspector/events/<event_id>. Интерфейс открывает это событие в деталях.
6. Шаблоны хранятся в аккаунте (до 100 на пользователя), с версией для безопасного редактирования: при конфликте версий клиент должен перечитать шаблон перед сохранением. Создание и обновление шаблона требуют только доступного вам tunnel_id; неактивный туннель или отключённый клиент не мешают сохранить сценарий — доставка проверяется только при Отправить тест и Run. Допустимые HTTP-методы: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. Удаление туннеля или inbox удаляет связанные шаблоны.
Подробные контракты API, коды ошибок и ограничения — в справочнике API, ошибках и известных ограничениях. Пользовательские истории — в отдельном документе.
Справочник API
Обзор
Ручные тестовые вебхуки и библиотека шаблонов доступны через REST API с префиксом /api/webhook-test-events. Все методы требуют авторизованной сессии дашборда (кука) или эквивалентной аутентификации.
Мутации из браузера с сессионной кукой дополнительно требуют заголовок X-CSRF-Token с значением из куки csrf_token (см. защита CSRF).
| Метод | Путь | Назначение |
| --- | --- | --- |
| GET | /api/webhook-test-events/builtins | Список встроенных неизменяемых примеров запросов |
| GET | /api/webhook-test-events/templates?tunnel_id=<id> | Список сохранённых шаблонов для эндпоинта |
| GET | /api/webhook-test-events/templates/<id> | Один сохранённый шаблон |
| POST | /api/webhook-test-events/templates | Создать шаблон из редактора |
| POST | /api/webhook-test-events/templates/from-event | Создать шаблон из события инспектора |
| PATCH | /api/webhook-test-events/templates/<id> | Обновить шаблон (с ожидаемой версией) |
| DELETE | /api/webhook-test-events/templates/<id> | Удалить шаблон |
| POST | /api/webhook-test-events/send | Отправить один ручной запрос |
| POST | /api/webhook-test-events/templates/<id>/run | Выполнить сохранённый шаблон |
Поддерживаются только HTTP/HTTPS-эндпоинты (HTTP-туннель или webhook inbox). TCP/UDP-туннели возвращают отказ.
Сохранение шаблонов и доставка: POST /templates, POST /templates/from-event и PATCH /templates/<id> проверяют владение эндпоинтом, но не требуют активной доставки (подключённого клиента или доступного режима inbox). POST /send и POST /templates/<id>/run проверяют текущую цель и при недоступности возвращают 409 с code: "endpoint_unavailable".
Область видимости: список и чтение шаблонов, событий и эндпоинтов ограничены вашим аккаунтом. Чужой или недоступный идентификатор возвращает 404 с code: "not_found" — без подтверждения существования ресурса.
---
Общая модель запроса (request)
Используется в создании шаблона, ручной отправке и в поле request шаблона.
| Поле | Тип | Описание |
| --- | --- | --- |
| method | строка | HTTP-метод: GET, POST, PUT, PATCH, DELETE, HEAD или OPTIONS (нормализуется к верхнему регистру). Другие методы (CONNECT, TRACE и т. п.) отклоняются при создании, обновлении и отправке |
| path | строка | Путь относительно эндпоинта, начинается с /; не абсолютный URL |
| raw_query | строка | Необязательная query-строка без ведущего ? |
| headers | массив | Элементы { "name", "value" }; запрещённые заголовки удаляются |
| content_type | строка | Необязательный Content-Type |
| body | строка | Необязательное тело; максимум 32 КБ после декодирования |
| body_encoding | строка | Кодирование поля body: text (по умолчанию, UTF-8 текст) или base64 (двоичные или не-UTF-8 данные). Неверная base64 → 400 invalid_request |
---
GET /api/webhook-test-events/builtins
Возвращает четыре встроенные примеры: Empty POST, JSON event, Invalid JSON, Missing field JSON. Их не редактируют и не удаляют через API.
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| builtins | Массив объектов с полями id, name, description, request |
---
GET /api/webhook-test-events/templates
Список сохранённых шаблонов только для одного эндпоинта. Параметр tunnel_id обязателен; без него или с недоступным эндпоинтом запрос отклоняется.
Параметры запроса
| Параметр | Обязательность | Описание |
| --- | --- | --- |
| tunnel_id | да | Идентификатор HTTP/HTTPS-туннеля или webhook inbox, принадлежащего вашему аккаунту |
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| templates | Массив объектов шаблона (может быть пустым) |
---
GET /api/webhook-test-events/templates/<id>
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| template | Объект шаблона |
Объект template:
| Поле | Описание |
| --- | --- |
| id | UUID шаблона |
| tunnel_id | Эндпоинт, к которому привязан шаблон |
| name | Имя (до 120 символов; уникально для эндпоинта без учёта регистра) |
| description | Описание (до 1000 символов) |
| tags | До 50 тегов |
| example_outcome | success, failure или unspecified |
| version | Целое число; увеличивается при каждом успешном обновлении |
| created_at, updated_at | Время в RFC3339 |
| request | Объект запроса (см. выше) |
Устаревшие методы в шаблоне: если шаблон был сохранён ранее с методом вне списка поддерживаемых, GET по-прежнему возвращает его как есть. Чтобы обновить или запустить такой шаблон, выберите поддерживаемый метод в редакторе или в API.
---
POST /api/webhook-test-events/templates
Создаёт новый шаблон. Тело очищается до сохранения.
Тело запроса (JSON)
| Поле | Описание |
| --- | --- |
| tunnel_id | Эндпоинт |
| request | Объект запроса |
| name | Имя шаблона |
| description | Необязательно |
| tags | Необязательный массив строк |
| example_outcome | Необязательно: success, failure, unspecified |
Успешный ответ 201
| Поле | Описание |
| --- | --- |
| template | Созданный шаблон (version = 1) |
| redacted_fields | Список путей замаскированных полей (например query.token, body.password) |
---
POST /api/webhook-test-events/templates/from-event
Создаёт шаблон из доступного HTTP-события инспектора. Исходное событие не изменяется.
Тело запроса (JSON)
| Поле | Описание |
| --- | --- |
| event_id | UUID события инспектора |
| name | Имя нового шаблона |
| description, tags, example_outcome | Необязательно |
| body | Необязательно: { "omit": true } или { "body": "…", "body_encoding": "text|base64" } для замены непрозрачного захваченного тела |
Успешный ответ 201
Как при создании шаблона: template и redacted_fields.
---
PATCH /api/webhook-test-events/templates/<id>
Обновление с оптимистичной блокировкой: поле version в теле должно совпадать с текущей версией в сервисе. При расхождении (параллельное редактирование) — 409 stale_version; перечитайте шаблон и повторите PATCH с актуальной version.
Тело запроса (JSON)
| Поле | Описание |
| --- | --- |
| version | Обязательно. Ожидаемая текущая версия шаблона (целое число из последнего GET) |
| name, description, tags, example_outcome | Необязательные поля для изменения |
| request | Необязательный полный объект запроса |
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| template | Обновлённый шаблон с version + 1 |
| redacted_fields | Замаскированные поля после санитизации |
---
DELETE /api/webhook-test-events/templates/<id>
Успешный ответ 204
Без тела.
---
POST /api/webhook-test-events/send
Отправляет один ручной запрос на текущую цель tunnel_id.
Тело запроса (JSON)
| Поле | Описание |
| --- | --- |
| tunnel_id | Эндпоинт |
| request | Объект запроса |
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| event_id | UUID нового события инспектора |
| delivered | true, если ответ от цели получен |
| downstream_status | HTTP-код ответа цели (если доставка выполнена) |
| duration_ms | Время доставки в миллисекундах |
| notes | Необязательная поясняющая строка (например режим «только хранение» или пауза доставки) |
| redacted_fields | Поля, замаскированные при отправке |
Событие помечается тегом webhook-test-event. Исход доставки зависит от режима эндпоинта: активный туннель — реальный ответ downstream; inbox «только хранение» или пауза — синтетическое «сохранено» без вызова локального сервиса; forward_local / forward_remote — по правилам webhook inbox. См. известные ограничения.
---
POST /api/webhook-test-events/templates/<id>/run
Выполняет сохранённый шаблон на текущей цели эндпоинта шаблона. Шаблон не изменяется.
Тело запроса
Пустой объект {} или пустое тело.
Успешный ответ 200
Как при send, плюс тег webhook-template:<template_id> на событии инспектора.
---
Подробнее об ошибках — в справочнике ошибок. Ограничения размера, квот и доставки — в известных ограничениях.
Ошибки
401 Unauthorized
Когда: запрос к /api/webhook-test-events/* без действующей сессии или с недействительными учётными данными.
Тело ответа (JSON): code: "unauthorized", сообщение о необходимости входа.
Что делать: войдите в личный кабинет или передайте корректную авторизацию, как для остальных API дашборда.
---
403 Forbidden — заблокированный аккаунт
Когда: аккаунт приостановлен.
Тело ответа (JSON): code: "user_suspended".
Что делать: обратитесь в поддержку для восстановления аккаунта.
---
403 Forbidden — функция недоступна на тарифе
Когда: на плане нет возможности webhook-test-events или панель скрыта политикой тарифа.
Тело ответа (JSON): code: "feature_disabled", сообщение о недоступности ручных тестов вебхуков.
Что делать: проверьте тариф в разделе оплаты или обновите план. В дашборде панель тестирования не отображается или показывает отказ при вызове API.
---
403 Forbidden — CSRF (браузерная сессия)
Когда: мутация (POST, PATCH, DELETE) с сессионной кукой без заголовка X-CSRF-Token или с неверным токеном.
Текст ответа: содержит csrf forbidden.
Что делать: для вызовов из браузера скопируйте значение куки csrf_token в заголовок X-CSRF-Token. Для чистого API-клиента с bearer-токеном правило может не применяться — следуйте общим правилам защиты CSRF.
---
404 Not Found
Когда:
- шаблон, событие инспектора или эндпоинт не существует;
- ресурс принадлежит другому пользователю или эндпоинт вам недоступен (намеренно без раскрытия существования);
- запрос списка шаблонов без
tunnel_id или с чужим/недоступным tunnel_id.
Тело ответа (JSON): code: "not_found".
Что делать: проверьте tunnel_id, event_id и id шаблона. Перечитайте список шаблонов после удаления эндпоинта. Не используйте идентификаторы из другого аккаунта.
---
409 Conflict — имя шаблона
Когда: создание или переименование шаблона с именем, которое уже используется на том же эндпоинте (без учёта регистра).
Тело ответа (JSON): code: "template_name_conflict".
В дашборде: «Шаблон с таким названием уже существует для этого endpoint.»
Что делать: выберите другое имя или удалите существующий шаблон.
---
409 Conflict — квота шаблонов
Когда: в аккаунте уже 100 сохранённых шаблонов (суммарно по всех эндпоинтов).
Тело ответа (JSON): code: "template_quota_exceeded".
В дашборде: «Достигнут лимит шаблонов для аккаунта.»
Что делать: удалите неиспользуемые шаблоны или объедините сценарии.
---
409 Conflict — лимит тегов
Когда: в шаблоне больше 50 тегов.
Тело ответа (JSON): code: "template_tag_limit".
В дашборде: «Достигнут лимит тегов для шаблона.»
Что делать: сократите список тегов.
---
409 Conflict — устаревшая версия
Когда: PATCH с полем version, которое не совпадает с текущей версией в сервисе (параллельное редактирование).
Тело ответа (JSON): code: "stale_version", сообщение о необходимости перечитать шаблон.
В дашборде: «Шаблон изменился в другом месте. Перезагрузите его перед сохранением.» Редактор предлагает перезагрузить последнюю версию.
Что делать: выполните GET /api/webhook-test-events/templates/<id>, обновите форму и отправьте patch с актуальной version.
---
409 Conflict — эндпоинт недоступен
Когда: при отправке (send) или запуске шаблона (run) туннель или inbox удалён, неактивен, истёк или иным образом недоступен для доставки. Сохранение и обновление шаблонов (POST/PATCH) этой проверкой не блокируется.
Тело ответа (JSON): code: "endpoint_unavailable".
В дашборде: «Текущий endpoint недоступен. Проверьте статус туннеля, подключение клиента и режим доставки inbox.»
Что делать: проверьте статус туннеля/inbox в дашборде, подключение клиента и режим доставки inbox. Шаблон можно сохранить заранее и запустить после восстановления доставки.
---
413 Payload Too Large
Когда: тело запроса в send или в шаблоне превышает 32 КБ.
Тело ответа (JSON): code: "body_too_large".
Что делать: уменьшите тело или разбейте сценарий на несколько запросов.
---
422 Unprocessable Entity — неподдерживаемый эндпоинт или запрос
Когда:
tunnel_id указывает на TCP/UDP-туннель или другой не-HTTP тип;
- запрос не соответствует правилам HTTP-эндпоинта.
Тело ответа (JSON): code: "unsupported_request".
Что делать: используйте HTTP/HTTPS-туннель или webhook inbox. Откройте инспектор только для HTTP-эндпоинта.
---
422 Unprocessable Entity — нужна ручная очистка тела
Когда: сохранение шаблона из события инспектора, у которого захваченное тело непрозрачно или обрезано, без явного omit или замены тела.
Тело ответа (JSON): code: "manual_sanitization_required".
Что делать: в диалоге «Сохранить как шаблон» отметьте «Не включать тело» или задайте замену; в API передайте body.omit или новое body.body.
---
400 Bad Request — невалидные поля
Когда:
- абсолютный или protocol-relative путь (
https://…, //…);
- HTTP-метод вне списка
GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS;
- неверный JSON в теле API;
- неверная base64 в
body_encoding;
- пустое имя, недопустимый
example_outcome, CR/LF в заголовках и другие нарушения валидации.
Тело ответа (JSON): code: "invalid_request" или сообщение о неверном кодировании поля.
Что делать: исправьте путь (только относительный, с /), метод, синтаксис JSON и значения полей. В панели инспектора поля остаются на экране для правки.
---
429 Too Many Requests
Когда: исчерпан лимит частоты HTTP-запросов для аккаунта или эндпоинта (общий с другими HTTP-операциями туннеля).
Тело ответа (JSON): code: "rate_limited".
Что делать: подождите и повторите отправку. Снизьте частоту автоматических прогонов шаблонов.
---
502 / 504 и коды от downstream
Когда: цель недоступна, таймаут или отказ при доставке на активный туннель.
Что делать: при успешном ответе API 200 смотрите downstream_status и детали события в инспекторе. Убедитесь, что клиент туннеля подключён и локальный сервис отвечает.
---
500 Internal Server Error
Когда: непредвиденная ошибка на стороне сервиса при обработке запроса.
Текст ответа: общее сообщение о внутренней ошибке без технических деталей.
Что делать: повторите операцию позже. Если ошибка сохраняется — обратитесь в поддержку с event_id (если был возвращён) и временем запроса.
Ограничения
Известные ограничения
Граница первой версии (личные шаблоны)
- Только владелец и эндпоинт. Сохранённые шаблоны привязаны к вашему аккаунту и одному
tunnel_id. Общих библиотек команды, среды (staging/production) или аккаунта нет — каждый эндпоинт имеет свою библиотеку.
- Чужие идентификаторы — 404. Запрос шаблона, события или эндпоинта другого пользователя или недоступного вам ресурса возвращает
not_found без раскрытия, существует ли объект.
- Без переноса между эндпоинтами. Чтобы тестировать другой URL, создайте новый шаблон на нужном эндпоинте.
Режимы доставки эндпоинта
Поведение send и run зависит от текущего состояния выбранного HTTP/HTTPS-туннеля или webhook inbox (цель не хранится в шаблоне):
| Режим | Что происходит при ручной отправке |
| --- | --- |
| Активный HTTP/HTTPS-туннель с подключённым клиентом | Запрос доставляется на локальную цель; в событии фиксируются реальный код и тело ответа downstream |
| Webhook inbox «только хранение» (store_only) | Локальный сервис не вызывается; создаётся синтетическое событие с ответом «сохранено» |
| Inbox или туннель на паузе | Как при «только хранение» — синтетическое сохранение без доставки на локальный сервис |
| Inbox «пересылка на локальный клиент» (forward_local) | Пересылка по правилам inbox; фиксируется ответ цели или ошибка отключённого клиента |
| Inbox «пересылка на удалённый HTTPS» (forward_remote) | Пересылка только на заранее одобренный HTTPS-адрес inbox (нужна соответствующая возможность тарифа) |
| Удалённый, недоступный или не-HTTP эндпоинт | Отказ (not_found, endpoint_unavailable или unsupported_request) без ложного «успешного» события |
Подробнее о webhook inbox.
Общие ограничения
- Только HTTP/HTTPS-эндпоинты. Ручные тесты и шаблоны недоступны для TCP/UDP-туннелей; панель в инспекторе не отображается на их страницах.
- Разрешённые HTTP-методы. При создании, обновлении и отправке допустимы только
GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. Старые шаблоны с другим методом (например CONNECT) можно прочитать, но перед сохранением или Run нужно выбрать поддерживаемый метод в редакторе.
- Сохранение шаблона ≠ доставка. Создание и обновление шаблона не требуют подключённого клиента или активной доставки inbox; Отправить тест и Run по-прежнему проверяют текущую цель и при недоступности возвращают
409 endpoint_unavailable.
- Вкладка «Тест» в инспекторе. Несохранённый ручной запрос сохраняется в форме при переключении на События или Настройки; выбор встроенного примера поверх изменённых полей требует подтверждения.
- Фиксированная цель. Запрос всегда идёт на текущую цель выбранного
tunnel_id. Нельзя указать внешний хост или абсолютный URL в поле пути.
- Размер тела 32 КБ. Более крупные payload отклоняются до отправки и до сохранения в шаблон.
- Квоты шаблонов. До 100 сохранённых шаблонов на аккаунт (все эндпоинты суммарно), до 50 тегов на шаблон, имя до 120 символов, описание до 1000 символов.
- Шаблон привязан к эндпоинту. Запуск шаблона всегда использует эндпоинт, с которым он был создан; перенос на другой URL требует создания нового шаблона.
- Удаление эндпоинта удаляет шаблоны. После удаления туннеля или inbox связанные шаблоны недоступны.
- Встроенные примеры неизменяемы. Список built-in можно только читать и копировать в редактор;
PATCH/DELETE по их id не сохраняют изменения.
- Санитизация заголовков и секретов.
Authorization, Cookie, Host, hop-by-hop и аналогичные заголовки не сохраняются и не отправляются. Ключи query и JSON, похожие на секреты, маскируются в шаблонах и в redacted_fields.
- Без настраиваемой политики маскировки. Нельзя задать отдельные правила скрытия полей для каждого эндпоинта или раскрывать секреты по запросу — действуют единые правила сервиса.
- Непрозрачное тело события. При сохранении шаблона из инспектора бинарное или обрезанное захваченное тело требует явного пропуска (
body.omit) или замены — автоматическое копирование блокируется (manual_sanitization_required). Вручную введённое непрозрачное тело в редакторе — ваш явный ввод; структурная очистка произвольного бинарного payload не гарантируется.
- Без гарантии «ровно один раз». Каждая успешная
send или run создаёт отдельное событие инспектора. Повтор того же запроса, повторная отправка после сетевого сбоя или двойной клик (интерфейс блокирует кнопку только на время запроса) может создать дубликат — встроенной идемпотентности и долговременного ключа дедупликации нет.
- Синхронная запись в инспектор. Ответ с
event_id выдаётся после фиксации события; при сбое записи инспектора операция завершается ошибкой, даже если downstream уже ответил.
- Лимит частоты HTTP. Действует общий ограничитель HTTP-запросов; частые ручные тесты могут получить
429.
- Доставка зависит от режима inbox и клиента. Inbox «только хранение» не вызывает локальный сервис; для пересылки нужен подключённый клиент или доступная remote-цель — как для обычного inbox-трафика (см. webhook inbox).
- Захват тел в инспекторе. Полное отображение request/response body в деталях события зависит от тарифа и настроек захвата тел; ручной тест не обходит эти правила.
- Тарифная функция. На планах без
webhook-test-events API и UI недоступны; на бесплатном плане функция обычно не включена.
- Отличие от Replay. Повтор запроса (Replay) воспроизводит существующее событие с его политикой подавления capture; ручной тест всегда создаёт новое синтетическое событие с тегом
webhook-test-event.
TCP Traffic Inspector
Описание
Общее описание функционала
Инспектор TCP-трафика даёт владельцу TCP-туннеля просматривать историю TCP-соединений, проходящих через туннель: адреса клиента и цели, длительность, объём трафика, состояние завершения и при необходимости укороченный захват потока в текстовом или шестнадцатеричном виде. Данные доступны в дашборде на странице инспектора туннеля (вкладка TCP) и через API с поддержкой потоковой подписки (SSE) для живых обновлений.
Как пользователь может использовать
- Разработчик отлаивает нестабильное TCP-приложение: открывает инспектор, сортирует соединения по времени, находит обрывы и ошибки.
- Пользователь проверяет, что внешний клиент действительно доходит до указанного целевого адреса, сверяя IP и порты в списке.
- Пользователь переключает отображение текст/hex для просмотра коротких текстовых протоколов поверх TCP.
- Пользователь фильтрует соединения по состоянию (активные, закрытые, ошибка) для фокуса на проблемных сессиях.
- Администратор при поддержке пользователя просматривает те же метаданные в рамках полномочий продукта.
- Инженер подписывается на SSE-поток, чтобы видеть новые соединения в реальном времени во время теста.
Как это реализовано в сервисе
При установке и закрытии TCP-соединения через туннель сервис фиксирует событие и сохраняет его в базе вместе с ограниченным объёмом перехваченных байт. Запросы из интерфейса дашборда или API проходят проверку владельца туннеля (или права администратора), затем возвращают страницу списка или одну запись. Поток событий рассылает новые записи подписчикам; частота опроса ограничивается лимитами сервера. В публичном развёртывании инспектор доступен только при корректной аутентификации и настройке режима работы, отличного от небезопасной отладочной конфигурации.
Справочник API
Список соединений
GET /api/v1/inspector/tcp/connections
Параметры:
tunnel_id (обязательный) — ID туннеля
from — начало периода (RFC3339)
to — конец периода (RFC3339)
state — фильтр по состоянию: active, closed, error
limit — лимит (по умолчанию 50)
offset — смещение
Ответ: { "connections": [...], "pagination": { "limit", "offset", "count", "has_more" } }
Получение соединения
GET /api/v1/inspector/tcp/connections/:id
Параметры:
format — text | hex (опционально, для формата stream_capture)
Ответ: объект TCPConnectionEvent с полями id, tunnel_id, client_ip, client_port, target_addr, started_at, ended_at, duration_ms, bytes_in, bytes_out, state, error_msg, stream_capture / stream_capture_text / stream_capture_hex
SSE-поток
GET /api/v1/inspector/tcp/connections/stream?tunnel_id=...
События: { "type": "tcp_connection", "data": TCPConnectionEvent }
Ошибки
Справочник ошибок
| Код | Сообщение | Условие |
|-----|-----------|---------|
| 401 | Unauthorized | Отсутствует или недействительна авторизация |
| 403 | Forbidden | Пользователь не имеет доступа к туннелю |
| 404 | TCP connection not found | Соединение не найдено |
| 503 | Service Unavailable | Сервис инспектора недоступен |
Ограничения
Известные ограничения
- Захват потока ограничен (по умолчанию 32 КБ на соединение)
- Guest-пользователи не имеют доступа к TCP-инспектору
- Клиентский IP в dataplane-пути может быть недоступен (отображается как «dataplane»)
- Отображение потока в текстовом формате может содержать замены для невалидного UTF-8
Риски конфигурации
- tls_insecure_skip_verify: При создании/изменении HTTPS-туннелей можно отключить проверку TLS-сертификата бэкенда. Это делает трафик уязвимым к MITM. Использовать только для доверенных внутренних целей (localhost, dev-сертификаты). Никогда не включать для ненадёжных или публичных бэкендов.
TCP туннели
Описание
Общее описание функционала
TCP-туннелирование открывает локальный TCP-сервис (SSH, база данных, произвольный бинарный протокол) для доступа с интернета через инфраструктуру туннеля. Трафик передаётся как поток байт с мультиплексированием по надёжному транспорту между клиентом и сервером; поддерживаются режим публичного порта на стороне сервиса и сценарий expose-local (внешний порт на сервере), когда внешние клиенты подключаются к выделенному порту, а агент пробрасывает соединение на локальную машину. Для протоколов с TLS на стороне приложения платформа не расшифровывает полезную нагрузку на границе (в отличие от HTTP(S)-туннеля с терминацией TLS на входе).
Как пользователь может использовать
- Разработчик открывает SSH к домашней машине для удалённой отладки.
- Команда подключается к общей базе данных на стенде разработчика через выданный
host:port.
- Пользователь поднимает туннель к промышленному устройству или SCADA по TCP.
- Пользователь использует режим expose-local (внешний порт на сервере), чтобы внешний партнёр подключился к порту на сервере туннелей, а трафик ушёл на
127.0.0.1 у владельца.
- Пользователь полагается на автоматические повторы при кратковременных обрывах транспорта между CLI и сервером.
- Пользователь входит в бесплатную учётную запись перед созданием TCP-туннеля; платный CLI-токен для этого не нужен.
- Входящие и исходящие данные TCP расходуют общий месячный лимит всех туннелей этой учётной записи.
- Администратор ограничивает доступ списками IP на уровне туннеля.
- Пользователь сравнивает с HTTP(S)-туннелем: для «короткой ссылки в браузере» чаще подходит HTTP-маршрут; для сквозного TLS приложения — TCP-туннель (см. пользовательские истории TCP).
- На macOS пользователь может сочетать expose-local TCP с локальным слушателем на
127.0.0.1 (например nc или опционально socat) для интерактивной TCP-сессии поддержки и отладки (см. US-12 и раздел Ограничения).
Как это реализовано в сервисе
Клиент сначала подтверждает зарегистрированную учётную запись, затем регистрирует туннель и получает публичный адрес:порт или инструкции для режима expose-local. Бесплатного тарифа достаточно, если его лимиты не исчерпаны. Плоскость данных устанавливает защищённый канал между сервером и CLI, через который байты копируются между сокетом в интернете и локальным приложением. Сервер выделяет порты из настроенного диапазона, применяет ограничения и учитывает полезные данные в обоих направлениях в общей месячной квоте владельца.
Как использовать через CLI-клиент
TCP-туннель создаётся с протоколом tcp и адресом локального TCP-сервиса. Пример для SSH на порту 22:
fortunnels tcp 22
или:
fortunnels -protocol tcp -local 127.0.0.1:22
Для входа без пароля в истории команд используйте стандартный ввод:
fortunnels tcp 22 -login user@example.test -pass-stdin
При исчерпании общего месячного трафика клиент завершает работу с подсказкой. Повторное создание туннеля не сбрасывает использование; дождитесь нового месяца или попросите администратора увеличить лимит.
Транспорт данных по умолчанию — WebSocket; альтернативы -dp quic и -dp dtls описаны в документации CLI-клиента.
Справочник API
Создание туннеля
POST /api/tunnels
Пример тела:
{
"protocol": "tcp",
"target_addr": "127.0.0.1:22"
}
Ответ содержит id, public_addr (или эквивалент host:port) и метаданные создания.
Требуется действующая сессия или Bearer-токен зарегистрированной учётной записи. Бесплатного тарифа достаточно в пределах его лимитов; гостевой TCP-режим недоступен.
Чтение и удаление
GET /api/tunnels?id={id} — получить один туннель (или GET /api/tunnels для списка).
PATCH /api/tunnels — обновить туннель; в теле JSON укажите id и поля/действие.
DELETE /api/tunnels?id={id} — удалить туннель.
Публичный вход
Внешний клиент открывает TCP на выданный public host:port; сервер сопоставляет поток с туннелем и клиентским агентом.
CLI
См. справку fortunnels для режима tcp и expose-local; глобальные флаги сервера, аутентификации и транспорта (-dp ws/quic/dtls) общие с другими протоколами.
Ошибки
Отказ в подключении
Целевой localhost порт закрыт — внешний клиент или CLI получают обрыв или сообщение об ошибке прокси в зависимости от стадии.
Превышен лимит одновременных соединений
Новые подключения к туннелю отклоняются или ожидают освобождения слота согласно политике сервера и тарифа.
ACL
Подключение с заблокированного IP отклоняется на входе туннеля.
Квоты и тариф
Создание или использование туннеля может быть отклонено с JSON 403 (квота, функция недоступна) по тем же правилам, что и HTTP-туннели.
Аутентификация
401 при обращении к API без учётных данных там, где они обязательны.
Ограничения
- Дополнительная задержка и джиттер по сравнению с прямым TCP неизбежны из-за туннелирования.
- Пул публичных портов ограничен настройками сервиса; исчерпание диапазона блокирует новые TCP-туннели.
- При паузе туннеля публичные соединения не обслуживаются до возобновления и переподключения клиента.
- Режим expose-local зависит от поддержки в CLI и на сервере; сетевой путь отличается от классического «публичный порт на сервере → локальный сервис».
- Не гарантируется сохранение долгих idle-соединений при агрессивных таймаутах NAT и прокси на пути.
- На macOS поведение интерактивной TCP-сессии зависит от выбранных утилит (BSD
nc vs GNU netcat, опционально socat): это не SSH; полноценный TTY и сигналы не гарантируются. Рекомендуется слушать только 127.0.0.1, а не 0.0.0.0. Типовой порядок: (1) запустить локальный слушатель, например nc -l 127.0.0.1 7777; (2) поднять TCP-туннель на этот порт; (3) удалённый клиент подключается к выданному публичному host:port.
Пауза туннеля
Общее описание функционала
Пауза TCP-туннеля временно закрывает публичный порт и завершает текущие соединения, не удаляя сам туннель и его адрес. Уже запущенный клиент может автоматически переподключаться и отправлять сигналы активности, но новые TCP-соединения не проходят до возобновления. После возобновления тот же туннель может снова работать без перезапуска клиента. Для владельца функция доступна на тарифе, который включает паузу; администратор сохраняет предусмотренные права управления.
Как пользователь может использовать
- Разработчик ставит туннель на паузу на ночь, чтобы временно закрыть публичный порт локального сервиса.
- Владелец оставляет клиент запущенным во время паузы и возобновляет тот же туннель, когда доступ снова нужен.
- Пользователь на Free видит пункт «Пауза» в меню действий неактивным и может перейти к смене тарифа из подсказки.
- Пользователь видит в дашборде статус «Приостановлен» и понимает, что новые подключения намеренно отключены.
- Команда прерывает долгую TCP-сессию паузой и открывает новое соединение после возобновления; прерванные данные автоматически не повторяются.
- Администратор приостанавливает туннель пользователя при инциденте.
- После возобновления пользователь подключается по тому же публичному адресу, когда автоматическое соединение клиента готово.
Как это реализовано в сервисе
Команда паузы сохраняет состояние «Приостановлен», закрывает публичный TCP-порт для новых подключений и завершает текущие соединения. Переподключения и сигналы активности клиента не отменяют паузу. Команда возобновления возвращает прежний публичный порт в работу и использует восстановившееся соединение клиента; если оно ещё не готово, порт остаётся недоступным до автоматического переподключения. Проверки прав и тарифа не меняются, а смена публичного адреса приостановленного TCP-туннеля по-прежнему требует сначала его возобновить.
Пауза и возобновление
PATCH /api/tunnels
Тело JSON включает идентификатор туннеля и поле действия:
action: pause — приостановить туннель.
action: resume — возобновить туннель.
Успех: ответ с обновлённым объектом туннеля (в т.ч. поле статуса paused / active) в формате вашего API.
Права: владелец туннеля или администратор.
Связанное действие
action: regenerate_url — для TCP в активном состоянии перевыделяет публичный порт; для приостановленного TCP может возвращаться ошибка с просьбой сначала выполнить resume (сообщение в теле ответа).
400 Bad Request
Недопустимое действие для текущего состояния (например, regenerate_url для TCP на паузе) — в теле JSON текст с подсказкой сначала resume.
401 / 403
Нет прав изменять туннель.
При code: feature_disabled и feature_id: tunnel-pause — функция Пауза туннеля не входит в текущий тариф (tunnel pause requires a paid plan). Нужно сменить тариф или обратиться к администратору.
TCP после resume
Пока клиент данных не восстановил готовое соединение, новое TCP-подключение не передаётся к локальной цели. Клиенту нужно повторить подключение после восстановления туннеля; HTTP-ответ 503 к TCP-входу не относится.
Ограничения
- На паузе новые TCP-подключения не принимаются, в том числе после автоматического переподключения клиента и его сигналов активности.
- TCP-соединения, открытые в момент паузы, завершаются. Сервис не сохраняет и не повторяет прерванные данные после возобновления.
- Если соединение клиента ещё не готово, после возобновления публичный порт остаётся недоступным до автоматического переподключения. Перезапуск клиента обычно не требуется.
- Публичный адрес приостановленного TCP-туннеля нельзя сменить до возобновления.
- Истёкший или закрытый туннель нельзя возобновить; вместо него нужно создать новый.
Traffic Inspector
Описание
Общее описание функционала
Инспектор HTTP-трафика сохраняет события HTTP/HTTPS-запросов, прошедших через туннель: метод, путь, код ответа, длительность и доступные по правилам захвата заголовки и тело. Владелец туннеля просматривает журнал в дашборде, открывает отдельное событие и при необходимости повторяет запрос с безопасными ограничениями на путь и заголовки.
Для события также определяется IP клиента. Заголовки переадресации учитываются только тогда, когда запрос пришёл через настроенный доверенный промежуточный сервер. В остальных случаях Инспектор показывает адрес прямого соединения. Чтобы адрес не повторялся на каждом небольшом экране, мобильные карточки и компактный список его не показывают. На широком экране он доступен в подробном списке, а у выбранного события — отдельной строкой IP клиента.
Как пользователь может использовать
- Разработчик отлаживает API: находит неудачный запрос в списке, открывает детали и сравнивает его с ответом бэкенда.
- Специалист поддержки открывает выбранное событие и сверяет IP клиента с ожидаемым источником запроса.
- Разработчик включает подробный вид на широком экране и сравнивает IP нескольких событий в одном списке.
- Пользователь работает с журналом на телефоне или в компактном режиме без повторения IP в каждой карточке или строке.
- Пользователь фильтрует события по туннелю, времени и пагинации, чтобы не загружать весь журнал.
- Пользователь подписывается на поток событий (SSE) для живого просмотра во время ручного теста.
- Пользователь запускает повтор запроса события в режиме «через облако» или «локально» с допустимыми правками тела/метода в рамках ограничений сервера.
- Администратор при поддержке просматривает те же события в рамках полномочий.
Как это реализовано в сервисе
Когда запрос проходит через публичный адрес туннеля, сервис определяет адрес клиента, проверяет правила доверия к промежуточному серверу и сохраняет событие Инспектора. Если адрес клиента передал доверенный посредник, порт соединения посредника не приписывается клиенту. Если доверенного посредника нет или заголовок содержит некорректный адрес, используется адрес прямого соединения.
Список и карточки получают те же данные события, но показывают их с разной плотностью. Подробный вид подходит для сравнения, а выбранное событие содержит одну основную строку IP клиента. Сохранённые заголовки переадресации остаются в разделе заголовков запроса и не подменяют эту строку. Доступ к списку и деталям проверяется по учётной записи и туннелю. Перед повтором запроса сервис отдельно проверяет допустимые изменения пути, заголовков и тела.
Справочник API
Список событий
GET /api/v1/inspector/events
Параметры (имена уточняйте по ответу сервера): tunnel_id, фильтры времени, пагинация limit / offset или курсор.
Ответ: JSON со списком событий и метаданными пагинации.
IP клиента
source_ip — определённый сервисом IP клиента. Имя поля сохраняется для новых и ранее записанных событий.
source_port — порт прямого соединения, если он был корректно определён. Для адреса, полученного от доверенного промежуточного сервера, поле отсутствует или равно null: порт такого соединения принадлежит посреднику, а не клиенту.
- Заголовки
X-Forwarded-For и X-Real-IP, если они попали в захват, остаются отдельными элементами списка заголовков запроса. Они не заменяют source_ip и сами по себе не означают, что сервис им доверял.
Фильтр по IP клиента в дополнении «Расширенный журнал инспектора» продолжает передавать параметр source_ip.
Одно событие
GET /api/v1/inspector/events/{id}
id должен быть URL-encoded в клиенте.
Поток SSE
GET /api/v1/inspector/events/stream?tunnel_id=...
Подписка на новые события; tunnel_id в query также передавать в закодированном виде при необходимости.
Повтор запроса
POST /api/v1/inspector/events/{eventId}/replay
Тело JSON: { "mode": "cloud" | "local", "overrides": { ... опционально } }.
cloud — повтор выполняется на сервере Fortunnels и уходит через публичный edge туннеля (как внешний клиент). Подходит для проверки маршрута end-to-end на fortunnels.ru.
local — повтор отправляется непосредственно в настроенную цель туннеля без нового внешнего обращения к публичному адресу.
Поля overrides (правки метода, пути, заголовков и тела) ограничены сервером: нельзя подставить абсолютный URL в path, запрещённые заголовки и слишком большое тело (лимит порядка десятков килобайт).
Ошибки
401 Unauthorized
Нет сессии или токена для инспектора (в боевом режиме).
403 Forbidden
Нет доступа к туннелю события.
400 Bad Request
Некорректные параметры списка или недопустимые правки запроса при повторе (путь, заголовки, размер тела).
404 Not Found
Событие не найдено или недоступно.
503 Service Unavailable
Инспектор отключён или хранилище недоступно.
Ограничения
- Захват может не включать полное тело запроса/ответа или маскировать чувствительные поля по политике сервера.
- Повтор запроса не гарантирует идентичный побочный эффект на бэкенде; использовать только на тестовых стендах с осторожностью.
- Большие журналы требуют фильтрации по времени и туннелю.
- В dev-режиме сервера правила аутентификации к инспектору могут быть слабее, чем в продакшене.
Inspector export and retention
Общее описание функционала
Дополнение «Экспорт и хранение инспектора» расширяет инспектор HTTP-трафика: пользователь на подходящем тарифе задаёт срок хранения событий (от нескольких дней до года), видит ориентировочную дату автоудаления и экспортирует записи в JSON, как сырую HTTP-транскрипцию или как команду cURL. Без дополнения журнал событий хранится 3 дня; экспорт и настройка срока недоступны. Очистка журнала или удаление одного события убирает только данные инспектора — публичный URL туннеля и приём нового трафика не затрагиваются. Настройки полного захвата тел и лимита размера тела связаны с дополнением «Захват тел запросов» и отображаются в той же панели на странице инспектора.
Как пользователь может использовать
- Разработчик на тарифе с дополнением открывает инспектор туннеля (
/dashboard/tunnels/{tunnelId}/inspector), в панели Хранение и экспорт видит текущий срок хранения, лимит тарифа (до 365 дней) и строку Ориентировочная дата автоудаления, задаёт новый срок (например, 30 дней) и нажимает Сохранить.
- Пользователь сравнивает значения в панели — срок в днях, лимит тарифа и Ориентировочную дату автоудаления — с полями
retention_days, plan_retention_days_max и next_auto_deletion_at из GET /api/v1/inspector/settings перед аудитом или отчётом.
- После Очистить все пользователь убеждается, что публичный URL туннеля остаётся прежним и новый трафик снова появляется в журнале.
- Интегратор выгружает одно событие через Export JSON в деталях или запросом
GET …/export?format=json для архива или тикета.
- Пользователь копирует Copy cURL (или скачивает
format=curl) и вставляет команду в терминал: публичный https URL, заголовки и тело подставляются автоматически; аргументы с символами оболочки (;, |, $() и т.п.) экранируются одинарными кавычками для безопасной вставки.
- Специалист поддержки получает raw HTTP транскрипт одного события (
format=raw) для обмена с внешней системой.
- Аналитик отправляет POST массовый экспорт JSON с массивом
event_ids (от 1 до 50 id): ответ всегда JSON-массив объектов событий, даже если передан один id.
- Пользователь без дополнения видит фиксированные 3 дня хранения; поле срока в панели недоступно, кнопки копирования и экспорта в деталях скрыты или недоступны по тарифу.
- Владелец туннеля нажимает Очистить все, в диалоге подтверждения читает, что публичный URL туннеля останется активным, подтверждает удаление только записей инспектора и проверяет, что новый трафик снова появляется в журнале.
- При удалении одного события пользователь подтверждает, что URL туннеля не изменится.
- В списке событий пользователь видит значки truncated (обрезано) и no body (тело не сохранено) и в деталях — пояснение Тело не захвачено (только метаданные) для режима только метаданных.
- Пользователь с низким лимитом тела проверяет частичное сохранение и значок Обрезано в деталях запроса.
- Администратор с правами экспорта обращается к тем же endpoint'ам API, что и обычный пользователь с дополнением на тарифе.
Как это реализовано в сервисе
Настройки инспектора (срок хранения, лимит тела, полный захват) сохраняются на аккаунт и при чтении сопоставляются с возможностями тарифа: без дополнения «Экспорт и хранение» действует короткий срок по умолчанию, запрошенный больший срок не применяется. Сервис периодически удаляет события старше эффективного срока каждого владельца; оценка следующего автоудаления в интерфейсе соответствует полуночи UTC плюс выбранное число дней. Экспорт и копирование читают те же детали события, что и экран детализации: JSON — полная структура, raw — текстовая HTTP-транскрипция, cURL — команда с публичным https адресом и экранированием аргументов для оболочки. Массовый экспорт доступен только в JSON (до 50 id); ответ всегда JSON-массив, в том числе при одном id. Формат HAR не поддерживается — при запросе сервис отвечает ошибкой с подсказкой использовать JSON, raw или cURL. Удаление и очистка затрагивают только журнал инспектора; записи туннеля и его публичный endpoint остаются.
Настройки инспектора — срок хранения и entitlements
GET /api/v1/inspector/settings
PUT /api/v1/inspector/settings
Требуется авторизация. Базовые поля захвата тел описаны в документации «Захват тел запросов». Дополнение «Экспорт и хранение» добавляет и изменяет следующие поля.
Ответ GET (и эффективные значения после PUT)
| Поле | Описание |
| --- | --- |
| retention_days | Эффективный срок хранения событий инспектора в днях. Без дополнения на тарифе всегда 3. С дополнением — сохранённое значение в пределах тарифного лимита. |
| plan_retention_days_max | Максимальный срок, разрешённый тарифом: 3 без дополнения, 365 с дополнением «Экспорт и хранение». |
| next_auto_deletion_at | Оценка момента автоудаления событий, зафиксированных «сегодня»: RFC3339, 00:00:00 UTC на дату через retention_days календарных дней от текущего UTC-дня. |
| export_retention_entitled | true, если на тарифе есть дополнение «Экспорт и хранение» (настройка срока выше 3 дней и экспорт API/UI). |
| body_capture_entitled | true, если на тарифе есть дополнение «Захват тел запросов» (см. связанную документацию). |
Поле PUT
| Поле | Описание |
| --- | --- |
| retention_days | Запрошенный срок в днях. Без export_retention_entitled сервер сохраняет 3 независимо от запроса. С дополнением значение ограничивается диапазоном 1 … plan_retention_days_max; значение выше лимита урезается до лимита (не ошибка). |
При PUT без права на захват тел full_capture_enabled сбрасывается в false (см. документацию захвата тел).
Успешный PUT возвращает JSON с status: "updated" и объектом settings с сохранёнными полями.
Максимальный размер тела запроса для PUT — 32 КиБ; больший объём отклоняется с 400 (см. ошибки).
Экспорт одного события
GET /api/v1/inspector/events/{id}/export
Параметр query format (необязательный):
| format | Ответ |
| --- | --- |
| json или пусто | application/json — полная детализация события (как в GET /api/v1/inspector/events/{id}). |
| raw | text/plain — текстовая HTTP-транскрипция запроса и ответа. |
| curl | text/plain — команда curl с публичным https URL, заголовками и --data-raw при сохранённом теле. Значения аргументов с символами оболочки (;, |, $(), кавычки и т.п.) оборачиваются в одинарные кавычки для безопасной вставки в терминал. |
Успех: 200. В заголовке Content-Disposition — вложение с префиксом имени inspector-event-{id} и суффиксом .json, .http или .sh в зависимости от формата.
Требуется дополнение «Экспорт и хранение» на тарифе (или права администратора).
Контроль доступа: экспорт разрешён только для событий туннелей, к которым у пользователя есть доступ. Отсутствующее событие, уже удалённое или принадлежащее чужому туннелю — ответ 404 Not Found с сообщением «event not found» (тот же вид ответа, что и для несуществующего id; не 403).
Лимит частоты: на каждый успешный запрос экспорта действует пер-пользовательский лимит; при превышении — 429 Too Many Requests («rate limit exceeded»).
Массовый экспорт JSON
POST /api/v1/inspector/events/export?format=json
Тело JSON:
{
"event_ids": ["<uuid>", "<uuid>"]
}
| Поле | Описание |
| --- | --- |
| event_ids | Обязательный массив id событий. Минимум 1, максимум 50 id. |
Максимальный размер тела запроса — 16 КиБ (включая длинные uuid в массиве). Больший объём — 400 без обработки экспорта.
Успех: 200, application/json — всегда JSON-массив объектов детализации событий (никогда одиночный объект), в том числе при одном элементе в event_ids. Content-Disposition с префиксом inspector-events и суффиксом .json.
Те же правила контроля доступа (чужой id → 404) и лимита частоты (429), что и для экспорта одного события.
Параметр format для bulk:
- json — поддерживается (можно опустить query: по умолчанию JSON).
- raw и curl — не поддерживаются для нескольких событий (см. ошибки).
Форматы har, yaml и другие неизвестные значения format — 400.
Интерфейс дашборда
Страница инспектора туннеля: /dashboard/tunnels/{tunnelId}/inspector.
| Элемент | Описание |
| --- | --- |
| Панель Хранение и экспорт (data-testid="inspector-retention-panel") | Текущий срок хранения, лимит тарифа (plan_retention_days_max), строка Ориентировочная дата автоудаления (из next_auto_deletion_at), поле Срок хранения (дней) (id="retention-days") и Сохранить (при export_retention_entitled; поле отключено без дополнения). |
| Панель Захват тел запросов | Лимит тела, переключатель полного захвата (при body_capture_entitled). |
| Детали события | Copy cURL, Copy headers, Copy body, Export JSON — при дополнении на тарифе. |
| Очистить все | Удаление всех событий туннеля в инспекторе; диалог подтверждения сообщает, что публичный URL туннеля останется активным и удаляются только записи инспектора. |
| Удалить (в деталях) | Удаление одного события; диалог подтверждения сообщает, что публичный URL туннеля не изменится. |
401 Unauthorized
Нет сессии или токена для API инспектора.
403 Forbidden
- Нет дополнения «Экспорт и хранение» на тарифе — экспорт (
GET …/export, POST …/events/export) недоступен.
- Нет доступа к настройкам инспектора другого аккаунта (для не-администратора).
400 Bad Request
event_ids отсутствует или пустой массив при POST /api/v1/inspector/events/export.
- Более 50 элементов в
event_ids — сообщение о лимите 50 событий.
- Тело
POST /api/v1/inspector/events/export больше 16 КиБ — запрос отклоняется до обработки экспорта.
- Тело
PUT /api/v1/inspector/settings больше 32 КиБ — запрос отклоняется до сохранения настроек.
- Некорректный uuid в
event_ids — «invalid event id in event_ids».
retention_days вне диапазона 1 … plan_retention_days_max при PUT настроек (после учёта тарифа).
body_limit_bytes вне диапазона 1024–1048576 (см. захват тел).
- Неподдерживаемый
format при экспорте (например har, yaml) — текст с указанием поддерживаемых форматов: json, raw, curl.
POST …/events/export с format=raw или format=curl и более чем одним id — raw/curl только для одного события.
- Некорректное JSON-тело запроса.
404 Not Found
- Событие для экспорта или удаления не найдено или уже удалено.
- Запрос экспорта по id события чужого туннеля (другой аккаунт) — тот же ответ 404 и то же сообщение «event not found», что и для несуществующего id (не 403, чтобы не раскрывать наличие чужих событий).
429 Too Many Requests
- Превышен лимит частоты экспорта для пользователя на
GET …/events/{id}/export или POST …/events/export.
- Текст ответа: rate limit exceeded.
- Подождите и повторите запрос; при частых выгрузках разбейте работу на несколько сессий.
405 Method Not Allowed
Неверный HTTP-метод для endpoint настроек или экспорта (например POST на GET …/events/{id}/export).
503 Service Unavailable
Инспектор или хранилище событий временно недоступны. Повторите запрос позже.
500 Internal Server Error
Внутренняя ошибка при чтении настроек, сохранении или построении экспорта. Если ошибка повторяется — обратитесь в поддержку.
Известные ограничения
- Без дополнения «Экспорт и хранение» срок хранения фиксирован на 3 дня;
plan_retention_days_max равен 3; настройка срока и экспорт недоступны.
- С дополнением максимальный срок хранения — 365 дней; запрос выше лимита урезается до лимита тарифа, а не отклоняется.
next_auto_deletion_at — только ориентировочная оценка по правилу «полночь UTC + retention_days» для событий, зафиксированных в текущий UTC-день; фактическое удаление выполняется фоновой задачей сервиса и может наступить позже в тот же календарный день или после него — не используйте это поле как точный дедлайн для compliance.
- Массовый экспорт JSON принимает не более 50 id в одном запросе; для большего числа событий нужны несколько запросов. Ответ всегда JSON-массив, даже если в
event_ids передан один id (не одиночный объект).
- Форматы raw и cURL доступны только для одного события (
GET …/events/{id}/export); bulk endpoint поддерживает только JSON.
- Формат HAR (HTTP Archive) не поддерживается и не планируется в текущей версии; запрос
format=har возвращает 400 с подсказкой использовать JSON, raw HTTP или cURL.
- Файлы экспорта (JSON, raw, cURL) содержат захваченные заголовки и тела запросов/ответов — в них могут оказаться токены, cookie, ключи API и другие секреты; храните выгрузки в защищённом месте, не публикуйте и не пересылайте без необходимости.
- Экспорт и кнопки копирования в дашборде требуют дополнение на тарифе; без него доступны только метаданные в списке и деталях по правилам базового инспектора.
- Содержимое экспорта совпадает с детализацией события: без полного захвата тел в экспорте не будет сохранённых тел (см. захват тел).
- Команда cURL и копирование из UI используют публичный
https host события; локальные или внутренние адреса не подставляются. Аргументы с символами оболочки экранируются одинарными кавычками — команда рассчитана на вставку в типичный Unix-shell, но не гарантирует корректность во всех оболочках и ОС.
- Очистка журнала и удаление события необратимы и не отменяют работу туннеля; публичный URL остаётся прежним.
- Значки truncated и no body в списке событий отражают политику захвата и лимит тела, а не ошибку экспорта.
- Администратор может экспортировать без отдельного дополнения на тарифе, но остаются ограничения форматов и лимита bulk.
Inspector advanced log UX
Общее описание функционала
Дополнение «Расширенный журнал инспектора» добавляет к инспектору HTTP-трафика поиск, точные фильтры, сортировку, закрепление событий и массовое удаление. Оно также открывает подробный вид списка с данными о доставке webhook-inbox. Без дополнения базовый Инспектор остаётся доступен: фильтры по методу, пути, статусу, времени и режиму захвата работают как раньше.
Поиск по сохранённым телам и переключатель Включая тела требуют дополнение «Захват тел запросов». Закрепления общие для всех пользователей с доступом к туннелю. Массовое удаление убирает только записи Инспектора и не меняет публичный адрес туннеля. Коды ошибок и ограничения описаны в справочнике ошибок и известных ограничениях.
Как пользователь может использовать
- Разработчик с дополнением открывает
/dashboard/tunnels/{tunnelId}/inspector, вводит текст в Поиск и находит событие по пути, фрагменту id, заметкам или значению заголовка без открытия каждой записи.
- Интегратор включает Включая тела и ищет строку, которая есть только в сохранённом JSON или тексте POST — после включения захвата тел.
- Специалист поддержки задаёт Статус от / Статус до (например 400–499) и Только ошибки, чтобы отфильтровать неуспешные ответы и ошибки доставки webhook-inbox.
- Аналитик сортирует список по Длительность ↓ или Статус ↑ и сравнивает медленные или проблемные запросы в одном экране.
- Пользователь указывает IP клиента, Заголовок и Значение заголовка, чтобы найти трафик конкретного клиента или запросы с определённым
Authorization / X-Request-Id.
- Тестировщик фильтрует по Query param и Подстрока в теле, чтобы изолировать один сценарий API среди потока запросов.
- Аналитик задаёт Длительность от/до (мс) и отбирает запросы с аномально долгим или быстрым ответом.
- Интегратор задаёт границы размера запроса, чтобы найти крупные POST или пустые запросы прямо в панели фильтров.
- Пользователь оставляет в верхней строке путь, метод, точный статус, поиск и сортировку, а по кнопке Фильтры открывает боковую панель с периодом захвата и подробными критериями. Число рядом с кнопкой показывает, сколько критериев уже применяется.
- Пользователь нажимает Очистить всё и одновременно сбрасывает базовые и расширенные критерии, не меняя выбранный вид списка и отмеченные события.
- Владелец туннеля закрепляет (Закрепить) ключевые события, включает Только закреплённые и собирает «короткий список» для демо или эскалации.
- Пользователь в другой сессии или браузере видит те же закрепления без повторного действия — состояние общее для туннеля.
- Оператор webhook-inbox переключает Подробный вид и читает delivery_status (
delivered, failed, pending) и destination_label для inbox-трафика без открытия каждой карточки.
- Пользователь выбирает несколько строк чекбоксами, подтверждает Удалить выбранные и очищает журнал от шума, оставляя туннель активным.
- Пользователь без дополнения продолжает работать с базовыми фильтрами инспектора; поиск, сортировка и расширенные критерии скрыты, а период и режим захвата по-прежнему доступны в панели фильтров.
- Администратор с правами доступа к туннелю использует те же API и элементы интерфейса, что пользователь с дополнением на тарифе.
- Пользователь сохраняет Компактный или Подробный вид списка — выбор сохраняется в браузере и восстанавливается после перезагрузки страницы.
- Разработчик включает Подробный вид на широком экране и сравнивает события по колонке IP клиента.
- Пользователь открывает событие и видит один основной адрес в строке IP клиента, а исходные заголовки переадресации — отдельно среди заголовков запроса.
- Пользователь просматривает журнал на телефоне без повторения IP в компактных и подробных карточках.
Как это реализовано в сервисе
Инспектор оставляет основные критерии в короткой строке, а подробные помещает в боковую панель. Список событий остаётся видимым, пока пользователь настраивает отбор. На узком экране поля прокручиваются внутри панели, а её заголовок и действия остаются доступными.
Расширенные элементы показываются только пользователям, которым дополнение доступно по тарифу. Фильтр IP клиента использует то же поле source_ip, что и API, поэтому сохранённые ссылки и интеграции продолжают работать. Сам адрес не повторяется в мобильных карточках и компактном списке. Он появляется в подробном списке на широком экране и один раз в метаданных выбранного события. При активном поиске или фильтре список обновляется как единая выборка и сохраняет заданные условия.
Расширенный список событий
GET /api/v1/inspector/events
Требуется авторизация. Базовые параметры списка (tunnel_id, method, status, path_sub / path_contains, capture, from / to, limit, offset) описаны в документации инспектора. Дополнение «Расширенный журнал инспектора» добавляет следующие query-параметры. Без дополнения на тарифе любой запрос с хотя бы одним из них возвращает 403 Forbidden (параметры не применяются молча).
| Параметр | Описание |
| --- | --- |
| source_ip | Подстрока IP клиента (регистронезависимое совпадение). |
| status_min, status_max | Диапазон HTTP-статуса ответа (целые числа). Работает вместе с точным status, если он задан. |
| min_duration_ms, max_duration_ms | Диапазон длительности запроса в миллисекундах. |
| min_request_size, max_request_size | Диапазон сохранённого размера тела запроса в байтах (метаданные захвата). |
| has_error | true — только события с HTTP ≥ 400 или признаками ошибки доставки/захвата. |
| header_name | Имя заголовка для поиска в заголовках запроса или ответа. |
| header_value | Подстрока значения заголовка; требует header_name. |
| query_param_key | Ключ query-параметра в URL запроса. |
| query_param_value | Подстрока значения query-параметра (часто вместе с ключом). |
| body_substring | Подстрока в сохранённом теле запроса; требует tunnel_id и захват тел. |
| search | Глобальный поиск: путь, фрагмент id, заметки, значения заголовков; без join тел по умолчанию. |
| search_include_bodies | true — включить поиск в сохранённых телах при непустом search (медленнее; нужен захват тел). |
| sort_by | ts (по умолчанию), status или duration_ms. |
| sort_dir | asc или desc (по умолчанию desc для ts). |
| pinned_only | true — только закреплённые события на туннеле. |
Параметры search и body_substring обязательно сопоставляются с tunnel_id. Длина шаблона search и body_substring — не более 200 символов.
Дополнительные поля в ответе списка
При наличии дополнения на тарифе (или для администратора) каждый элемент списка может содержать:
| Поле | Описание |
| --- | --- |
| pinned | true, если событие закреплено на туннеле. |
| short_id | Первые 8 символов id события для компактного отображения. |
| request_size | Размер сохранённого тела запроса в байтах (0, если тело не сохранено). |
| delivery_status | Для webhook-inbox: delivered, failed, pending или пусто для обычного HTTP-трафика. |
| destination_label | Подпись назначения inbox (forward URL, local client, store only); учётные данные в URL скрыты. |
Успех: 200 с JSON списка и метаданными пагинации.
Закрепление события
POST /api/v1/inspector/events/{id}/pin
Требуется дополнение на тарифе (или права администратора). {id} — UUID события, URL-encoded.
Успех: 204 No Content. На туннеле действует лимит 50 закреплённых событий.
Снятие закрепления
DELETE /api/v1/inspector/events/{id}/pin
Требуется дополнение. Повторный вызов для уже незакреплённого события также успешен (204).
Массовое удаление
POST /api/v1/inspector/events/delete
Требуется дополнение. Тело JSON:
{
"tunnel_id": "<tunnel_id>",
"event_ids": ["<uuid>", "<uuid>"]
}
| Поле | Описание |
| --- | --- |
| tunnel_id | Обязательный id туннеля (можно также передать в query tunnel_id). |
| event_ids | Обязательный массив id событий: минимум 1, максимум 50 UUID. Все id должны принадлежать указанному туннелю. |
Успех: 200 с JSON {"deleted": <число удалённых записей>}. Удаляются события, сохранённые тела и закрепления для этих id; публичный URL туннеля не меняется.
Интерфейс дашборда
Страница: /dashboard/tunnels/{tunnelId}/inspector.
| Элемент | Описание |
| --- | --- |
| Поиск | Глобальный поиск; подсказка в поле: «Путь, ID, заголовки, заметки…». |
| Включая тела | Переключатель поиска в сохранённых телах; по умолчанию выключен (соответствует search_include_bodies=false). |
| Сортировка | Варианты: Время ↓/↑, Длительность ↓/↑, Статус ↓/↑. |
| Расширенные фильтры | IP клиента, Статус от/до, Длительность от/до (мс), Заголовок, Значение заголовка, Query param, Подстрока в теле, Только ошибки, Только закреплённые. Поле IP клиента передаёт прежний query-параметр source_ip. |
| Очистить фильтры | Сбрасывает базовые и расширенные фильтры, поиск и сортировку. |
| Компактный вид / Подробный вид | Переключение плотности журнала; настройка сохраняется в браузере. |
| IP клиента в журнале | В компактном списке и мобильных карточках IP не повторяется. В подробном списке на широком экране есть одна колонка IP клиента. У выбранного события адрес показан одной строкой в метаданных. |
| Закрепить / Открепить | Действие над записью журнала. |
| Чекбоксы строк | Множественный выбор; не более 50 — сообщение «Можно выбрать не более 50 событий». |
| Удалить выбранные (N) | Подтверждение «Удалить выбранные события (N)? Действие необратимо.» |
Панель поиска, расширенные фильтры и массовое удаление отображаются только при дополнении на тарифе.
401 Unauthorized
Нет сессии или токена для API инспектора.
403 Forbidden
- Нет дополнения «Расширенный журнал инспектора» на тарифе — расширенные query-параметры списка,
POST/DELETE закрепления и POST …/events/delete недоступны.
- Нет доступа к указанному
tunnel_id при массовом удалении.
- В
event_ids указаны id событий другого туннеля — запрос отклоняется целиком, без частичного удаления.
400 Bad Request
event_ids отсутствует или пустой массив при POST /api/v1/inspector/events/delete.
- Более 50 элементов в
event_ids — текст «event_ids exceeds limit of 50».
- Некорректный UUID в
event_ids — «invalid event id in event_ids».
tunnel_id не указан при массовом удалении — «tunnel_id required».
search или body_substring без tunnel_id — «tunnel_id required for body/search filters».
- Длина
search или body_substring более 200 символов — «search pattern too long».
header_value без header_name — «header_name required when header_value is set».
- Недопустимый
sort_by — «invalid sort_by» (разрешены только ts, status, duration_ms).
- Недопустимый
sort_dir — «invalid sort_dir» (разрешены asc и desc).
- Некорректное целое в
status_min, status_max, min_duration_ms, max_duration_ms, min_request_size, max_request_size — соответствующие сообщения invalid ….
- Некорректное булево в
has_error, pinned_only или search_include_bodies — invalid has_error, invalid pinned_only или invalid search_include_bodies.
- Некорректное JSON-тело при массовом удалении — «invalid request body».
404 Not Found
- Событие для закрепления не существует.
- Событие принадлежит туннелю, к которому у вызывающего нет доступа (ответ 404, а не 403, чтобы не раскрывать существование id).
409 Conflict
- Попытка закрепить событие, когда на туннеле уже 50 закреплённых записей — «pin quota exceeded». Старые закрепления не снимаются автоматически.
405 Method Not Allowed
Неверный HTTP-метод для endpoint закрепления или массового удаления.
503 Service Unavailable
Инспектор или хранилище событий временно недоступны («inspector service not available»). Повторите запрос позже.
500 Internal Server Error
Внутренняя ошибка при фильтрации, закреплении или удалении. Если ошибка повторяется — обратитесь в поддержку.
Известные ограничения
- Без дополнения «Расширенный журнал инспектора» расширенные параметры списка, закрепление и массовое удаление недоступны; базовые фильтры инспектора работают как до дополнения.
- На каждый туннель — не более 50 закреплённых событий; при превышении новое закрепление отклоняется (409), без автоматического снятия старых.
- Закрепления общие для всех пользователей с доступом к туннелю (endpoint-scoped), не персональные.
- Массовое удаление — не более 50 id в одном запросе; в интерфейсе выбор строк также ограничен 50.
- Шаблоны
search и body_substring — не длиннее 200 символов.
- Поиск и фильтр Подстрока в теле находят только сохранённые тела; нужны дополнение «Захват тел запросов» и соответствующий режим захвата.
- Переключатель Включая тела по умолчанию выключен; поиск по умолчанию не читает большие payload'ы — запросы с телами могут выполняться медленнее.
- Колонки
delivery_status и destination_label вычисляются при каждом отображении списка на основе данных события и актуальных настроек webhook-inbox; подпись назначения может измениться, если настройки inbox обновили после захвата события. Отдельная история попыток доставки и счётчик попыток пока не отображаются.
- Фильтр по диапазону размера запроса (
min_request_size / max_request_size) доступен только через API — в панели расширенных фильтров дашборда его нет.
- Сравнение событий и массовый replay для выбранных строк не реализованы — для множественного выбора доступно только удаление.
- При активном расширенном запросе (поиск, фильтры или сортировка не по времени ↓) новые события из потока в реальном времени не добавляются в начало списка — список перезагружается с сервера.
- Очистить фильтры сбрасывает и базовую строку, и расширенную панель (поиск, расширенные поля, сортировку).
- Компактный / подробный вид сохраняется только в браузере на этом устройстве — на другом устройстве или в другом браузере настройка не переносится.
- IP клиента не показывается в мобильных карточках и компактном списке. Для сравнения адресов используйте подробный вид на широком экране; у выбранного события адрес остаётся доступен в метаданных.
- Массовое удаление и удаление через API необратимы и не останавливают туннель; публичный URL остаётся прежним.
- Администратор может использовать расширенные API без отдельного дополнения на тарифе, но лимиты 50 на закрепления, удаление и длину поиска сохраняются.
Request body capture
Общее описание функционала
Дополнение «Захват тел запросов» сохраняет тела HTTP-запросов и ответов для событий инспектора трафика в пределах лимита размера и настроек пользователя. Метаданные события (метод, путь, код ответа, заголовки) доступны на всех тарифах с инспектором; полные тела — только при включённой функции на тарифе и при активированном полном захвате в настройках инспектора. Сохранённые тела отображаются в деталях события в дашборде и подгружаются по запросу к API; их можно использовать при повторе вебхука, если тело не было обрезано лимитом.
Как пользователь может использовать
- Разработчик на тарифе с захватом тел включает полный захват в настройках инспектора и просматривает JSON тела входящего вебхука в панели деталей события.
- Пользователь задаёт лимит размера тела (от 1 КиБ до 1 МиБ) и проверяет, что большие запросы сохраняются частично с пометкой об обрезке.
- Интегратор сравнивает тело ответа целевого сервиса с исходным запросом в одном экране инспектора.
- Пользователь без функции на тарифе продолжает видеть только метаданные событий; полные тела не сохраняются даже при попытке включить захват в настройках.
- Владелец туннеля удаляет одно событие или очищает весь журнал туннеля — вместе с сохранёнными телами.
- Пользователь повторяет вебхук с сохранённым телом запроса (см. повтор вебхуков), не вводя тело вручную, если оно сохранено целиком.
Как это реализовано в сервисе
При прохождении HTTP-запроса через туннель сервис фиксирует метаданные события для инспектора. Если тариф и настройки пользователя разрешают полный захват, сервис дополнительно сохраняет ограниченные фрагменты тел запроса и ответа отдельно от строки события в списке. Список и поток событий остаются лёгкими; полное содержимое тел загружается при открытии детали события или при обращении к API детали. При удалении события или очистке журнала туннеля связанные тела удаляются вместе с записью. Повтор запроса может подставить сохранённое тело автоматически, если оно не обрезано; иначе требуется явное тело в параметрах повтора.
Настройки инспектора
GET /api/v1/inspector/settings
PUT /api/v1/inspector/settings
Требуется авторизация. Поля, связанные с захватом тел:
| Поле | Описание |
| --- | --- |
| full_capture_enabled | true — сохранять тела запросов и ответов при наличии функции на тарифе; false — только метаданные. |
| body_limit_bytes | Максимум байт на одно тело (запрос или ответ), от 1024 до 1048576 (1 МиБ). Если не задано, применяется значение по умолчанию 65536 (64 КиБ). |
На тарифе без дополнения «Захват тел запросов» события остаются с capture_level: metadata; тела не сохраняются независимо от full_capture_enabled.
Детали события с телами
GET /api/v1/inspector/events/{id}
Помимо полей события из базового инспектора, при сохранённых телах в ответе могут быть:
| Поле | Описание |
| --- | --- |
| request_body / response_body | Метаданные: captured, bytes_saved, truncated, content_type, при обрезке — bytes_original. |
| request_body_content / response_body_content | Содержимое: encoding (utf-8 или base64), text для текстовых типов, raw_base64 для бинарных, для multipart/form-data — список multipart_files с именами и размерами частей. |
| capture_level | full при сохранённых телах, иначе metadata. |
| truncated | true, если хотя бы одно тело обрезано лимитом. |
Тела не включаются в список событий и в SSE-поток — только в ответ детали.
Удаление событий и тел
DELETE /api/v1/inspector/events/{id}
Удаляет одно событие и все связанные сохранённые тела. Успех: 204 No Content. Нет доступа к туннелю: 403. Событие не найдено: 404.
DELETE /api/v1/inspector/events?tunnel_id={tunnelId}
Удаляет все HTTP-события инспектора для указанного туннеля и их тела. Успех: JSON с полем deleted (число удалённых записей). Параметр tunnel_id обязателен.
Связь с повтором вебхука
POST /api/v1/inspector/events/{eventId}/replay — при полном сохранённом теле запроса поле overrides.body можно не указыать; сервис отправит сохранённые байты. Подробности — в документации повтора вебхуков.
401 Unauthorized
Нет сессии или токена для API инспектора.
403 Forbidden
Нет доступа к туннелю события или к настройкам чужого аккаунта. Удаление чужого события отклоняется без изменения данных.
400 Bad Request
body_limit_bytes вне диапазона 1024–1048576 при сохранении настроек.
- Некорректные параметры запроса (например, отсутствует
tunnel_id при массовом удалении).
404 Not Found
Событие не найдено или уже удалено.
503 Service Unavailable
Инспектор или хранилище событий временно недоступны. Повторите запрос позже.
Повтор с обрезанным телом
При вызове повтора вебхука без overrides.body для события с обрезанным сохранённым телом запроса — 400 с сообщением о том, что тело было обрезано и нужно указать тело в параметрах повтора. Подробнее — в ошибках повтора вебхуков.
Известные ограничения
- Полный захват тел доступен только на тарифах с дополнением «Захват тел запросов» и при
full_capture_enabled: true в настройках инспектора.
- Без функции на тарифе события всегда остаются на уровне метаданных, даже если полный захват включён в настройках.
- На каждое тело (запрос и ответ отдельно) действует лимит
body_limit_bytes; превышающая часть не сохраняется, в метаданных выставляется truncated: true.
- Значение по умолчанию лимита — 64 КиБ, если пользователь не задал другое в допустимом диапазоне.
- Бинарные и нетекстовые типы содержимого в API детали отдаются в кодировке base64, а не как читаемый текст.
- Для
multipart/form-data в детали перечисляются метаданные частей (имя, имя файла, тип, размер); полное содержимое каждой части может быть недоступно при обрезке.
- Сохранённые тела не попадают в список событий и поток SSE — только в запрос детали события.
- Автоматический повтор вебхука с сохранённым телом невозможен, если тело запроса было обрезано; нужно передать
overrides.body вручную (до 32 КиБ).
- Удаление события или очистка журнала туннеля необратимо удаляет и сохранённые тела.
UDP Traffic Inspector
Описание
Общее описание функционала
Инспектор UDP-трафика позволяет владельцу UDP-туннеля просматривать проходящие датаграммы: направление (к клиенту или к бэкенду), адреса, размер полезной нагрузки, время и при необходимости укороченное содержимое пакета с текстовой/шестнадцатеричной подсказкой и эвристическим разбором известных протоколов. Данные накапливаются на стороне сервиса и доступны через API и вкладку инспектора у туннеля. Гостевой режим не имеет доступа к UDP-инспектору.
Как пользователь может использовать
- Разработчик отлаивает DNS, игровой UDP или кастомный протокол: открывает инспектор туннеля, вкладку UDP, фильтрует по времени и направлению, смотрит цепочку запрос/ответ между клиентом и локальным сервисом.
- Пользователь ищет конкретный поток по flow_key или подстроке адреса, чтобы отделить один клиент от другого.
- Администратор при расследовании инцидента запрашивает датаграммы пользователя по user_id (через админские параметры API), не смешивая чужие туннели без полномочий.
- Инженер подписывается на поток событий (SSE) для живого мониторинга во время нагрузочного теста.
- Пользователь открывает карточку датаграммы по идентификатору, чтобы увидеть полные метаданные и анализ полезной нагрузки, если она сохранена и не обрезана политикой размера.
- Сопровождение сверяет, что после изменения конфигурации туннеля трафик действительно доходит до бэкенда, сравнивая метки времени и направления в списке.
Как это реализовано в сервисе
Трафик UDP-туннеля проходит через серверный прокси датаплана: при обмене датаграммами сервис фиксирует метаданные и ограниченный фрагмент содержимого и сохраняет запись в хранилище инспектора. Запросы из дашборда или внешнего клиента API проходят аутентификацию и проверку доступа к туннелю (владелец или администратор). Список поддерживает фильтры и постраничность; отдельный запрос отдаёт одну запись с дополнительным разбором полезной нагрузки; поток событий доставляет новые записи по подписке. Частота запросов может ограничиваться лимитами, чтобы защитить сервер от злоупотреблений.
Справочник API
Список датаграмм
GET /api/v1/inspector/udp/datagrams
Основные параметры запроса:
tunnel_id — фильтр по туннелю (для не-админа обычно обязателен для осмысленной выборки и проверки доступа)
from, to — границы времени (RFC3339)
direction — направление потока
flow_key — ключ потока
addr_contains — подстрока в адресе
search, search_payload, field_contains — расширенный поиск (при поиске по полезной нагрузке действуют более строгие лимиты выборки)
limit, offset — пагинация
Ответ: JSON с массивом datagrams и объектом pagination (лимит, смещение, признак наличия следующих страниц).
Для администратора допускается параметр user_id для выборки в разрезе другого пользователя (см. поведение сервера в продакшене).
Одна датаграмма
GET /api/v1/inspector/udp/datagrams/{id}
id — UUID записи.
Ответ: метаданные записи; при наличии сохранённой полезной нагрузки — поля вроде payload, hex_dump, utf8_preview, analysis, а также parsed_summary / metrics, если заполнялись.
Поток SSE
GET /api/v1/inspector/udp/datagrams/stream
Опционально tunnel_id для фильтрации событий.
События с типом, соответствующим UDP-датаграммам (например udp_datagram), с телом в формате JSON.
Ошибки
401 Unauthorized
Пользователь не аутентифицирован или используется гостевой доступ — для UDP-инспектора он не допускается.
403 Forbidden
Аутентифицированный пользователь не имеет права на указанный туннель (чужой туннель без роли администратора).
400 Bad Request
Некорректные параметры фильтра (например, невалидный JSON в field_contains) или отсутствует идентификатор датаграммы в пути там, где он обязателен.
404 Not Found
Запись с указанным UUID не найдена или недоступна текущему пользователю.
429 Too Many Requests
Сработали лимиты частоты для API инспектора UDP.
503 Service Unavailable
Сервис инспектора отключён или хранилище недоступно.
500 Internal Server Error
Внутренняя ошибка при чтении или кодировании ответа. Повторить позже.
Ограничения
- Полезная нагрузка датаграммы обрезается на уровне сервера: длинные пакеты в списке и в деталях могут отображаться не полностью; точный предел задаётся конфигурацией сервера.
- Поиск, включающий содержимое полезной нагрузки, дороже обычного списка; сервер может снижать максимальный
limit выборки.
- Разбор протоколов носит эвристический характер и не заменяет специализированные анализаторы.
- В режиме разработчика правила аутентификации к инспектору могут отличаться от боевого режима; в продакшене требуется строгая аутентификация и настроенные лимиты.
UDP туннели
Описание
Общее описание функционала
UDP-туннелирование пересылает датаграммы между локальным UDP-сервисом и клиентами в интернете через инфраструктуру туннеля. Подходит для DNS, syslog, игровых протоколов и других сценариев, где важна низкая задержка и модель «без установления соединения», с пониманием, что потери и порядок остаются на совести UDP. Сервер выделяет публичный UDP-порт в заданном диапазоне и сопоставляет потоки по правилам сессий и ключей потока.
Как пользователь может использовать
- Разработчик публикует локальный DNS-резолвер или тестовый UDP-сервис для команды.
- Администратор собирает syslog или метрики с удалённых хостов на локальный коллектор.
- Пользователь подключается к игровому или стриминговому UDP-сервису за NAT.
- Пользователь задаёт в CLI локальный UDP listen и целевой адрес на стороне сервера согласно документации.
- Пользователь учитывает таймаут неактивности и максимальный размер датаграммы, настроенные оператором.
- Пользователь входит в бесплатную учётную запись перед созданием UDP-туннеля; гостевой режим для UDP недоступен.
- Отправленные и полученные датаграммы расходуют общий месячный лимит всех туннелей этой учётной записи.
Как это реализовано в сервисе
Клиент подтверждает зарегистрированную учётную запись, создаёт туннель с протоколом UDP и использует выбранный транспорт для передачи трафика. Бесплатного тарифа достаточно, если его лимиты не исчерпаны. Сервер слушает UDP на выделенном порту, сопоставляет пакеты с туннелем и пересылает их через защищённый канал к локальному приложению. Полезные данные каждой датаграммы учитываются один раз в нужном направлении; служебные данные транспорта в лимит не входят.
Как использовать через CLI-клиент
Основной сценарий — публикация локального UDP-сервиса (как в ngrok):
fortunnels udp 9000
fortunnels udp 192.168.1.10:9000
Клиент создаёт туннель, подключается к data-plane по WebSocket/smux и пересылает входящие датаграммы с публичного UDP-порта на локальный адрес.
Расширенный режим reverse-proxy (оба флага обязательны):
fortunnels udp 53 -udp-listen :5353 -udp-dst 127.0.0.1:53
UDP всегда требует учётную запись. Передайте действующий токен либо используйте -login user@example.test -pass-stdin. Подробности флагов -udp-listen и -udp-dst — в документации CLI-клиента.
Справочник API
Создание туннеля
POST /api/tunnels
Пример:
{
"protocol": "udp",
"target_addr": "127.0.0.1:5353"
}
Ответ: идентификатор туннеля и публичный UDP-адрес (схема udp://host:port или поля host/port — как возвращает ваш сервер).
Создание требует действующую сессию или Bearer-токен зарегистрированной учётной записи. Бесплатного тарифа достаточно в пределах его лимитов; гостевой UDP-режим недоступен.
Статус и удаление
GET / DELETE по контракту API туннелей с идентификатором (см. актуальные пути в справочнике сервера).
CLI
fortunnels в режиме udp с флагами локального прослушивания и удалённого назначения (см. -udp-listen, -udp-dst в справке клиента).
Инспектор UDP
Просмотр записанных датаграмм: GET /api/v1/inspector/udp/datagrams (отдельная возможность продукта; требует прав зарегистрированного пользователя, не гостя).
Ошибки
Датаграмма слишком большая
Пакет превышает udp_max_payload_bytes сервера — отбрасывается или не пересылается (наблюдаемо как отсутствие ответа на стороне UDP).
Нет свободного порта
Не удаётся выделить порт из udp_port_range — создание туннеля завершается ошибкой API.
Таймаут неактивности
Поток UDP закрыт после простоя; следующая датаграмма может инициализировать новый поток или быть потеряна в зависимости от клиента.
401 / 403 на API
Создание или управление без прав или при запрете протокола политикой.
Ограничения
- UDP не гарантирует доставку и порядок; приложение должно это учитывать.
- NAT и файрволы могут ограничивать входящий UDP к клиенту агента.
- Диапазон публичных портов и лимиты размера задаются конфигурацией; нет отдельного глобального «выключателя UDP» в современной модели — доступ контролируется диапазоном, ACL и протоколом туннеля.
- Устаревшие флаги вроде -udp-enabled у сервера не используются; их наличие в скриптах приведёт к ошибке запуска.
Webhooks & Replay
Описание
Общее описание функционала
Повтор запроса (Replay) позволяет безопасно отправить заново входящий HTTP-запрос, который был зафиксирован инспектором трафика на вашем туннеле — например, вызов вебхука от внешнего сервиса. Запрос уходит только на настроенную цель этого туннеля; произвольные внешние адреса недоступны.
Как пользователь может использовать
- Разработчик получил вебхук с ошибкой 500, находит событие в инспекторе и повторяет запрос на локальный сервис после исправления кода.
- Пользователь меняет путь или добавляет тестовое тело запроса, чтобы воспроизвести сценарий без повторного вызова извне.
- Пользователь сравнивает код ответа и время ответа после повтора с исходным событием.
- Владелец туннеля проверяет обработчик вебхука на staging-окружении через туннель.
Как это реализовано в сервисе
Сервис восстанавливает метод, путь и безопасные заголовки из сохранённого события, применяет ваши правки и отправляет запрос через тот же туннель на его целевой адрес. Если на тарифе включён захват тел запросов и тело запроса сохранено целиком, оно подставляется автоматически; иначе тело можно указать вручную в форме повтора или в overrides.body. Обрезанное сохранённое тело не отправляется без явной подстановки. Учётные данные, cookies и служебные заголовки удаляются. Результат повтора (код ответа и длительность) возвращается сразу в интерфейсе.
Справочник API
API
Повтор запроса
POST /api/v1/inspector/events/{eventId}/replay
Требуется авторизация и доступ к туннелю события. Доступна на тарифах с функцией «Webhooks & Replay».
Тело запроса
| Поле | Описание |
| --- | --- |
| mode | Необязательно, устарело. Значения cloud и local эквивалентны — запрос идёт на цель туннеля. |
| overrides.method | Необязательный HTTP-метод. |
| overrides.path | Необязательный путь и query (должен начинаться с /). Заменяет путь и query из события. |
| overrides.headers | Необязательные дополнительные заголовки (без cookies, Authorization, Host и др.). |
| overrides.body | Необязательное тело запроса (до 32 КБ). Если не указано и для события сохранено полное тело запроса (захват тел на тарифе), используется сохранённое значение. При обрезанном сохранённом теле поле обязательно. |
Успешный ответ 200
| Поле | Описание |
| --- | --- |
| event_id | Идентификатор исходного события. |
| downstream_status | HTTP-код ответа целевого сервиса. |
| duration_ms | Время доставки в миллисекундах. |
| delivered | true, если ответ от цели получен. |
Подробнее — в разделе ограничения повтора вебхука.
Ошибки
Ошибки
| Ситуация | HTTP | Сообщение (пример) |
| --- | --- | --- |
| Нет входа | 401 | unauthorized |
| Нет доступа к туннелю / функции | 403 | forbidden |
| Событие не найдено | 404 | event not found |
| Событие не пригодно для повтора | 400 | event is not replayable |
| Сохранённое тело запроса обрезано, а overrides.body не указано | 400 | stored request body was truncated; provide a body override to replay |
| Событие обрезано политикой захвата (уровень метаданных) | 400 | cannot replay truncated event |
| Недопустимый путь или заголовок в overrides | 400 | описание валидации |
| Туннель не активен или клиент не подключён | 400 / 503 | tunnel is not active / tunnel client is not connected |
| Превышен лимит запросов | 429 | rate limit exceeded |
| Цель недоступна (таймаут, отказ) | 502 / 504 | понятная подсказка шлюза |
| Внутренняя ошибка | 500 | internal server error |
Ответ 4xx или 5xx от целевого сервиса при успешной доставке возвращается в поле downstream_status с кодом 200 у API повтора.
Ограничения
Известные ограничения
- Повторяются только HTTP/HTTPS-события, помеченные как пригодные для повтора.
- Тело запроса при повторе: если на тарифе включён захват тел и тело сохранено без обрезки — подставляется автоматически; если тело не сохранялось (только метаданные) — нужно указать
overrides.body или поле в форме повтора; если тело было обрезано лимитом захвата — автоматический повтор блокируется до явной подстановки тела.
- Назначение фиксировано: целевой адрес туннеля из события, без выбора другого хоста.
- Заголовки авторизации, cookies, Host и hop-by-hop не передаются и не могут быть добавлены через overrides.
- Для повтора клиент туннеля должен быть подключён; иначе доставка невозможна.
- Действует лимит частоты запросов и ограничение по времени ожидания ответа цели.
Compare attempts & bulk / alternate replay
Общее описание функционала
Сравнение и массовый повтор дополняют базовый Replay в инспекторе трафика.
Пользователь может сопоставить два сохранённых события и увидеть различия в методе, адресе, заголовках, теле, статусе и длительности — без раскрытия секретов в теле, query или заголовках. Можно повторить выбранную группу событий одной операцией и отправить запросы на текущую цель туннеля, на порт этой же цели или на заранее разрешённый HTTPS-адрес облачного inbox. Для каждой попытки сервис сохраняет отдельный результат в инспекторе и связывает его с исходным событием.
Одиночный повтор через форму события остаётся совместимым: в ответе event_id всегда указывает на исходное событие, а поля попытки (attempt_event_id, attempt_number, root_event_id) добавляются рядом.
Как пользователь может использовать
- Откройте туннель → Инспектор → События, выберите два события и нажмите Сравнить, чтобы проверить, что изменилось между двумя вызовами вебхука.
- В диалоге сравнения читайте пометки у тела (
missing, invalid_json, text, truncated, unavailable, masked_full, available) — они описывают доступность данных, а не ошибку API.
- Выберите несколько событий и запустите Массовый повтор, если нужно прогнать один и тот же обработчик на всей выборке.
- Задайте режим Только ошибочные или временной диапазон, чтобы повторить подходящую группу без ручного отбора.
- Оставьте назначение Текущая цель туннеля, если запрос должен идти на адрес, настроенный для туннеля.
- Откройте Другой адрес и укажите Порт цели, если нужен другой порт на той же принадлежащей вам цели (хост и схема задаются туннелем, не вводятся вручную).
- Выберите Удалённый HTTPS, если запрос должен попасть на разрешённый HTTPS-адрес под самым длинным префиксом inbox, который принадлежит вам; query, учётные данные и fragment в адресе не допускаются.
- Следите за счётчиками в карточке задания; после завершения откройте ссылку на попытку, чтобы увидеть статус и вернуться к исходному событию.
- Нажмите Отменить: ещё не отправленные элементы станут
cancelled; для запроса, который уже ушёл, но итог не подтверждён, результат будет unknown; завершённые попытки не отзываются.
- Используйте стабильный заголовок
X-Fortunnels-Replay-ID на стороне получателя, если нужна дедупликация при повторной доставке.
Массовый повтор работает по модели «не менее одного раза»: после сбоя процесса один и тот же запрос может быть доставлен повторно с тем же идентификатором повтора. Сервис не обещает доставку «ровно один раз».
Как это реализовано в сервисе
Сервис проверяет право пользователя видеть туннель и каждое событие, затем фиксирует состав массового задания. Для каждого элемента создаётся отдельная попытка с неизменяемой ссылкой на исходное событие. Результат попытки отображается в инспекторе; исходное событие не изменяется.
При сравнении сервис возвращает только защищённые представления тел и очищенные заголовки. Секреты из тела, query и чувствительных заголовков не попадают в ответ сравнения. Перед отправкой на альтернативный адрес проверяются тарифные возможности, принадлежность адреса и правила безопасного соединения; при отказе сервис не раскрывает, существует ли чужой объект. Задания можно отменять; незавершённые элементы возвращаются в работу после истечения срока ожидания.
Сравнение событий
POST /api/webhook-replay/compare
Сравнивает два события, доступных текущему пользователю. Требуется авторизация, функция «Webhooks & Replay» с дополнением сравнения и массового повтора, CSRF-токен для запросов из браузера.
Тело запроса:
{
"left_event_id": "<uuid>",
"right_event_id": "<uuid>"
}
Успешный ответ 200:
| Поле | Описание |
| --- | --- |
| left_event_id, right_event_id | Сравниваемые события |
| truncated | true, если хотя бы одна сторона ограничена по размеру при сравнении |
| diffs | Список различий по полям |
Элемент diffs:
| Поле | Описание |
| --- | --- |
| field | Имя поля (method, path, query, header:…, request_body, response_status, response_body, duration_ms и др.) |
| left, right | Защищённые значения сторон (маскированные для тел и чувствительных заголовков) |
| equal | Совпадают ли значения |
| kind | scalar, header, json или text |
| left_note, right_note | Пометка доступности тела на каждой стороне (см. ниже) |
Пометки тела (left_note / right_note) — данные ответа, не HTTP-ошибка:
| Пометка | Смысл |
| --- | --- |
| available | Тело доступно для сравнения |
| missing | Тело не было сохранено |
| unavailable | Тело не удалось прочитать из хранилища |
| masked_full | Тело доступно только в защищённом виде |
| truncated | Сохранённое или сравниваемое тело обрезано по лимиту |
| invalid_json | Тело не является валидным JSON |
| text | Тело сравняется как текст, не как JSON |
Секреты из тела, query и чувствительных заголовков не возвращаются в ответе сравнения.
Одиночный повтор (совместимость)
POST /api/v1/inspector/events/{eventId}/replay
Поведение базового Replay сохранено. В успешном ответе 200 поле event_id всегда указывает на исходное событие. Дополнительные поля попытки:
| Поле | Описание |
| --- | --- |
| attempt_event_id | Идентификатор нового события попытки в инспекторе |
| attempt_number | Порядковый номер попытки для корневого события |
| root_event_id | Идентификатор корневого (исходного) события |
Полный контракт одиночного повтора — в документации Webhooks & Replay.
Массовый повтор
POST /api/webhook-replay/jobs
Создаёт задание массового повтора. Требуется авторизация, доступ к туннелю и функция «Webhooks & Replay» с дополнением массового повтора. Для запросов из браузера также требуется CSRF-токен.
Общие поля:
| Поле | Описание |
| --- | --- |
| tunnel_id | Идентификатор туннеля пользователя |
| selector_mode | selected, failed_only или time_range |
| event_ids | Список событий для режима selected |
| from, to | Границы времени в формате RFC 3339 для режима time_range |
| destination_kind | current, local_port или remote_https |
| local_port | Порт от 1 до 65535 для local_port (только порт; хост и схема берутся из цели туннеля) |
| remote_url | HTTPS-адрес без query, учётных данных и fragment для remote_https; путь должен находиться под самым длинным префиксом inbox, принадлежащим вызывающему |
Назначения:
| destination_kind | Поведение |
| --- | --- |
| current | Целевой адрес туннеля, как при обычном Replay |
| local_port | Тот же хост и схема, что у цели туннеля, но указанный порт; произвольный хост не допускается |
| remote_https | Разрешённый HTTPS-адрес облачного inbox; перенаправления не выполняются; для тарифа нужен доступ к удалённой пересылке |
За одно задание принимается не более 500 событий. Для одного пользователя одновременно может быть не более пяти активных заданий.
Ответ 200 содержит объект job с идентификатором, состоянием, режимом выбора, назначением, счётчиками total_count, succeeded_count, failed_count, skipped_count, cancelled_count, unknown_count и пояснением о доставке «не менее одного раза`.
Состояние и отмена
GET /api/webhook-replay/jobs/{jobId}
Возвращает состояние и счётчики задания. Терминальные состояния задания: completed, completed_with_errors, cancelled.
POST /api/webhook-replay/jobs/{jobId}/cancel
Запрашивает отмену задания. Элементы, которые ещё не отправлены, переходят в cancelled. Запрос, который уже ушёл, но итог доставки не подтверждён, обозначается как unknown. Завершённые попытки сохраняются.
Список заданий
GET /api/webhook-replay/jobs?tunnel_id=<tunnelId>
Возвращает задания указанного туннеля текущего пользователя.
Каждая завершённая попытка доступна через ссылку в инспекторе и содержит стабильный идентификатор X-Fortunnels-Replay-ID для дедупликации на стороне получателя.
Ошибки сравнения и массового повтора
| Ситуация | HTTP | Что сделать |
| --- | --- | --- |
| Не выполнен вход | 401 | Войдите в аккаунт и повторите запрос. |
| Функция недоступна по тарифу или аккаунт приостановлен | 403 | Проверьте тариф и состояние аккаунта. Для удалённой HTTPS-цели включите доступ к удалённой пересылке inbox. |
| Событие, туннель, задание или удалённый адрес недоступны текущему пользователю | 404 | Проверьте идентификатор и права доступа. Сервис намеренно не раскрывает существование чужих объектов — ответ не отличается от «не найдено». |
| Неверный режим выбора, UUID, порт или адрес назначения | 400 | Исправьте поля запроса. Для local_port передавайте только порт. Для remote_https используйте разрешённый HTTPS-адрес без query, учётных данных и fragment, под вашим префиксом inbox. |
| Сохранённое тело обрезано | 400 | Укажите новое тело явно в форме повтора или в overrides.body. |
| Слишком много событий или активных заданий | 400 или 409 | Уменьшите выборку (лимит 500 событий на задание, 5 активных заданий на пользователя), дождитесь завершения активного задания и повторите операцию. |
| Превышен лимит запросов | 429 | Подождите и повторите позже. |
| Цель не отвечает или отклонила соединение | 502 или 504 | Проверьте доступность цели туннеля или удалённого inbox. Запись о неудачной попытке останется в задании. |
| Запрос отменён во время доставки | 200 | Откройте результат элемента: он может быть cancelled или unknown, если итог доставки нельзя подтвердить. |
| Внутренняя ошибка сервиса | 500 | Повторите операцию. Если ошибка сохраняется, обратитесь в поддержку. |
HTTP-ответ целевого сервиса не означает ошибку API повтора: код цели записывается в результате попытки и доступен в инспекторе.
Пометки тела при сравнении (не ошибки)
Поля left_note и right_note в ответе POST /api/webhook-replay/compare описывают доступность тела на каждой стороне. Они не сопоставляются с HTTP-кодами ошибки.
| Пометка | Когда появляется | Что ожидать |
| --- | --- | --- |
| missing | Тело не было сохранено для события | Сравнение по телу ограничено; секреты не раскрываются |
| unavailable | Тело не удалось прочитать | Повторите сравнение позже; при постоянной ошибке обратитесь в поддержку |
| masked_full | Доступно только защищённое представление | Различия видны в маскированном виде |
| truncated | Тело обрезано по лимиту сравнения | Полное содержимое может быть недоступно в сравнении |
| invalid_json | Тело не является валидным JSON | Сравнение выполняется как текст, не как структурированный JSON |
| text | Тело сравняется как текст | Нормальный режим для не-JSON содержимого |
| available | Тело доступно для сравнения | Обычный случай при сохранённом теле |
Известные ограничения
- За одно массовое задание можно выбрать не более 500 событий; одновременно у пользователя может быть не более пяти активных заданий.
- Выборки
failed_only и time_range фиксируются при создании задания. Новые события не добавляются в уже созданное задание.
- Сервис доставляет запросы не менее одного раза. При сбое после отправки возможна повторная доставка с тем же
X-Fortunnels-Replay-ID. Доставка «ровно один раз» не гарантируется.
- Событие с обрезанным телом нельзя повторить автоматически без явного нового тела.
- Сравнение ограничивает размер каждой стороны. Большие тела показываются с пометкой
truncated.
- Пометки тела при сравнении (
missing, unavailable, masked_full, truncated, invalid_json, text, available) различаются и не объединяются в одну категорию.
- Секреты из тела, query и чувствительных заголовков не предназначены для просмотра через сравнение; в ответе только защищённые представления.
- Для
local_port хост и схема берутся из принадлежащей пользователю цели туннеля; указать произвольный хост нельзя — только порт.
- Удалённая цель (
remote_https) должна быть разрешена для пользователя, использовать HTTPS, находиться под самым длинным принадлежащим префиксом inbox и пройти проверки безопасного соединения. Query, учётные данные и fragment в адресе не допускаются. Перенаправления не выполняются.
- При отказе по правам или принадлежности удалённого адреса сервис отвечает как при «не найдено», без раскрытия существования чужого объекта.
- Отмена не отзывает запрос, который уже был отправлен. Его итог сохраняется как доставленный, ошибочный или
unknown, если результат доставки не подтверждён. Ещё не отправленные элементы переходят в cancelled.
- Одиночный повтор сохраняет совместимость:
event_id в ответе всегда указывает на исходное событие; поля попытки (attempt_event_id, attempt_number, root_event_id) добавляются отдельно.
Гостевой доступ
Описание
Общее описание функционала
Гостевой доступ позволяет создать туннель без регистрации и входа: пользователь сразу получает URL туннеля к локальному сервису. Это снижает порог для демонстраций, быстрых вебхуков и разовых задач. Гостевой туннель живёт ограниченное время, имеет лимит объёма трафика и не даёт полноценного управления в дашборде; зарегистрированные пользователи получают расширенные возможности и контроль.
Как пользователь может использовать
- Новый пользователь запускает CLI без логина и получает URL для демо локального сайта коллегам.
- Разработчик проверяет вебхук стороннего сервиса, отправляя URL гостевого туннеля во внешнюю систему.
- Посетитель открывает выданный URL туннеля в браузере без аккаунта на платформе и видит ответ локального сервиса владельца туннеля.
- Пользователь исчерпывает лимит времени или трафика и создаёт новый гостевой туннель для следующей задачи.
- Пользователь решает зарегистрироваться, чтобы получить постоянные туннели, список в дашборде и функции тарифа.
Как это реализовано в сервисе
Запрос на создание туннеля без учётных данных обрабатывается плоскостью управления как особый тип учётной записи: выдаются короткоживущие параметры (срок жизни, потолок трафика), туннель появляется в той же подсистеме маршрутизации, что и именованные туннели. Публичный вход проксирует HTTP(S) или другие протоколы по правилам продукта; гость не видит инспектор и административные разделы. После истечения срока или лимита туннель перестаёт принимать трафик; управление «списком гостевых туннелей» в интерфейсе не предусмотрено — идентификация идёт по выданному URL.
Как использовать через CLI-клиент
Если на сервере включён гостевой режим, туннель можно создать без входа и без CLI-токена — укажите адрес сервиса и локальный порт приложения:
fortunnels http 8080
Клиент создаст краткоживущий туннель с лимитами времени и трафика; URL туннеля появится в выводе. Для TCP или UDP используйте соответствующий протокол (fortunnels tcp 22, fortunnels udp 53 с нужными UDP-флагами). Ограничения гостевого режима описаны выше; полный список флагов — в документации CLI-клиента.
Справочник API
Создание гостевого туннеля
POST /api/tunnels
Тело JSON: те же поля, что и для обычного создания (protocol, целевой адрес и т.д.), см. общую справку по API туннелей.
Без заголовка Authorization и без сессионной куки — если гостевой режим разрешён на сервере.
Ответ: данные туннеля с URL туннеля (в ответе API — поле public_url), время истечения, сведения о лимите трафика — в форме, которую возвращает ваш экземпляр сервера.
Доступ посетителя к URL
GET / POST / другие методы на URL туннеля (поддомен из ответа API) — без входа на платформу; поведение определяется типом туннеля и локальным сервисом.
Ограничения для гостя
Эндпоинты дашборда, инспектора трафика и админки требуют зарегистрированного пользователя; гостевой токен URL не заменяет сессию для этих API.
Ошибки
Отказ в создании гостевого туннеля
Сервер отключил гостевой режим или превышена внутренняя квота — 4xx/5xx с телом JSON или текстом по политике развёртывания.
Туннель истёк или исчерпан трафик
Запросы к URL туннеля возвращают страницу или JSON с сообщением о недоступности; нужно создать новый гостевой туннель.
401 на защищённых API
Попытка вызвать пользовательский API дашборда без регистрации — ожидаемое поведение для гостя.
Ограничения
- Ограниченный срок жизни туннеля (типично до 24 часов).
- Ограниченный объём трафика на туннель; при исчерпании туннель останавливается до срока.
- Нет списка гостевых туннелей в личном кабинете; сохраняйте выданный URL самостоятельно.
- Нельзя приостанавливать, удалять или настраивать гостевой туннель через дашборд тем же способом, что у зарегистрированного пользователя.
- Инспектор трафика и расширенная аналитика недоступны гостю.
- Протоколы и лимиты гостя задаются конфигурацией сервера и могут отличаться между развёртываниями.
Облачный inbox webhook
Описание
Общее описание функционала
Облачный webhook inbox — постоянный публичный HTTPS-адрес для приёма вебхуков от внешних провайдеров (платёжные системы, CRM, мессенджеры и т.д.) без обязательного подключения локального клиента туннеля. Каждый inbox привязан к вашему аккаунту, имеет собственный URL и режим доставки: только сохранение с подтверждением провайдеру, пересылка на локальный сервис через подключённый клиент или пересылка на внешний HTTPS-эндпоинт (при наличии соответствующей опции тарифа).
Входящие запросы фиксируются в инспекторе HTTP-трафика с меткой webhook inbox. При сбое доставки провайдер по-прежнему получает успешное подтверждение (HTTP 200), чтобы избежать лавины повторных отправок; детали ошибки видны вам в инспекторе.
Функция доступна на тарифах с возможностью webhook-inbox. Количество inbox на аккаунт ограничено лимитом тарифа. Пересылка на удалённый HTTPS-URL требует дополнительной опции webhook-inbox-remote-forward.
Как пользователь может использовать
- Разработчик нажимает Создать endpoint, получает публичный адрес без запущенного локального клиента и просматривает тестовые вебхуки в инспекторе.
- Интегратор даёт провайдеру стабильный URL inbox в режиме «только хранение», пока бэкенд ещё не готов к приёму трафика.
- Команда с подключённым клиентом туннеля пересылает вебхуки на
127.0.0.1:3000 и видит реальный HTTP-код ответа локального сервиса.
- Пользователь с опцией удалённой пересылки направляет вебхуки на staging-сервер по HTTPS без постоянного локального туннеля.
- QA ставит доставку на паузу, чтобы накопить события в инспекторе, не беспокоя downstream-сервис.
- Владелец аккаунта меняет режим или адрес назначения через API или дашборд — публичный URL inbox при этом не меняется.
- Оператор копирует
public_url из раздела Туннели → Webhook inbox и вставляет его в настройки провайдера.
- Пользователь сравнивает повторные доставки через повтор запроса (Replay) после исправления обработчика на локальной стороне.
- Разработчик проверяет подпись или заголовки провайдера на сохранённых событиях в инспекторе до включения пересылки.
- Команда ограничена одним inbox на бесплатном тарифе — создаёт новый только после удаления старого туннеля или смены плана с большим лимитом.
- Владелец больше не использует endpoint и на странице
/dashboard/webhook-inbox выбирает его, нажимает Удалить endpoint и подтверждает необратимое удаление. После подтверждения endpoint исчезает из списка, а его публичный URL перестаёт принимать webhook-запросы.
Как это реализовано в сервисе
1. Вы создаёте inbox в личном кабинете или через API POST /api/webhook-inboxes. Сервис выдаёт постоянный публичный URL и сохраняет настройки режима.
2. Провайдер отправляет HTTP-запрос (любой метод и путь) на этот URL. Запрос не требует входа на платформу.
3. Сервис распознаёт трафик как inbox, записывает событие в инспектор (тело, заголовки, метаданные) и в зависимости от режима:
- Только хранение — отвечает провайдеру HTTP 200;
- Локальная пересылка — при подключённом клиенте передаёт запрос на указанный локальный адрес и возвращает провайдеру код ответа upstream; если клиент недоступен — сохраняет событие и отвечает HTTP 200;
- HTTPS пересылка — при наличии опции тарифа отправляет запрос на настроенный HTTPS-URL и при успехе возвращает провайдеру код ответа удалённого сервиса; при ошибке доставки — HTTP 200 и запись об ошибке в инспекторе.
4. Флаг пауза доставки останавливает пересылку, но приём и запись в инспектор продолжаются; провайдер по-прежнему получает HTTP 200.
5. Изменения режима, адреса назначения и паузы применяются через PATCH /api/webhook-inboxes или кнопки в дашборде; публичный URL остаётся прежним.
6. Когда endpoint больше не нужен, его можно удалить в дашборде. После подтверждения действие нельзя отменить: endpoint удаляется из списка, а публичный URL навсегда перестаёт принимать webhook-запросы. Дашборд показывает подтверждение успешного удаления.
Подробности API — в справочнике API. Коды ошибок — в справочнике ошибок. Ограничения — в известных ограничениях.
Справочник API
Обзор
Управление облачными webhook inbox выполняется через REST API под префиксом /api/webhook-inboxes. Все методы требуют авторизованной сессии (кука) или эквивалентной аутентификации дашборда.
Приём вебхуков от внешних провайдеров идёт на публичный URL inbox (public_url из ответа API) — без авторизации, любым HTTP-методом и с любым путём после хоста.
| Метод | Путь | Назначение |
| --- | --- | --- |
| GET | /api/webhook-inboxes | Список inbox текущего пользователя |
| POST | /api/webhook-inboxes | Создать inbox |
| PATCH | /api/webhook-inboxes?id=<tunnel_id> | Изменить режим, назначение или паузу доставки |
Другие HTTP-методы на /api/webhook-inboxes возвращают 405 Method Not Allowed.
Удаление endpoint относится к общему жизненному циклу туннеля, а не к этому набору методов.
---
GET /api/webhook-inboxes
Список всех inbox, принадлежащих авторизованному пользователю.
Успешный ответ 200
Тело JSON:
| Поле | Тип | Описание |
| --- | --- | --- |
| inboxes | массив | Список объектов inbox (может быть пустым) |
Каждый элемент массива inboxes:
| Поле | Тип | Описание |
| --- | --- | --- |
| tunnel_id | строка | Идентификатор inbox (используется в PATCH ?id=) |
| public_url | строка | Публичный HTTPS-URL для провайдера |
| mode | строка | store_only, forward_local или forward_remote |
| remote_forward_url | строка | HTTPS-URL назначения (для forward_remote; иначе пусто) |
| target_addr | строка | Локальный адрес назначения (для forward_local; иначе служебное значение) |
| delivery_paused | boolean | true — пересылка отключена, приём и запись в инспектор продолжаются |
| created_at | строка (RFC3339) | Время создания |
| updated_at | строка (RFC3339) | Время последнего изменения |
---
POST /api/webhook-inboxes
Создаёт новый inbox и выдаёт публичный URL.
Требуется возможность тарифа webhook-inbox и свободная квота max_webhook_inboxes.
Тело запроса (JSON)
| Поле | Обязательность | Описание |
| --- | --- | --- |
| mode | необязательно | Режим доставки. По умолчанию store_only. Допустимые значения: store_only, forward_local, forward_remote |
| target_addr | необязательно | Для forward_local: адрес локального сервиса, например 127.0.0.1:3000 |
| remote_forward_url | обязательно для forward_remote | Полный HTTPS-URL внешнего эндпоинта, например https://api.example.com/hooks |
Для режима forward_remote требуется опция тарифа webhook-inbox-remote-forward. URL должен использовать схему HTTPS; адреса localhost, частных и служебных сетей отклоняются при создании.
Успешный ответ 201 Created
Тело — один объект inbox (те же поля, что в списке выше).
---
PATCH /api/webhook-inboxes?id=<tunnel_id>
Частичное обновление существующего inbox. Параметр id в query обязателен и равен tunnel_id.
Публичный URL (public_url) не меняется при обновлении.
Тело запроса (JSON)
Все поля необязательны; передаются только изменяемые:
| Поле | Описание |
| --- | --- |
| mode | Новый режим: store_only, forward_local, forward_remote |
| target_addr | Новый локальный адрес для forward_local |
| remote_forward_url | Новый HTTPS-URL для forward_remote |
| delivery_paused | true — приостановить пересылку; false — возобновить |
Те же правила тарифа и валидации HTTPS-URL, что при создании, применяются при смене режима или remote_forward_url.
Успешный ответ 200
Тело — обновлённый объект inbox.
---
DELETE /api/tunnels?id=<tunnel_id>
Удаляет endpoint через общий API жизненного цикла туннелей. Используйте tunnel_id из списка inbox. После успешного удаления его публичный URL навсегда перестаёт принимать webhook-запросы, а endpoint исчезает из списка.
Успешный ответ 204 No Content
Тело ответа отсутствует.
Для работы в интерфейсе откройте /dashboard/webhook-inbox, выберите endpoint, нажмите Удалить endpoint и подтвердите действие. Удаление необратимо.
DELETE /api/webhook-inboxes не поддерживается.
---
Публичный приём вебхуков (public_url)
Внешний провайдер отправляет запросы на public_url с любым путём и query, например:
POST https://<ваш-поддомен>/hooks/payment
Авторизация на платформе не требуется.
Поведение ответа провайдеру
| Режим | Успешная доставка | Сбой доставки или пауза |
| --- | --- | --- |
| store_only | HTTP 200, пустое тело | — |
| forward_local | HTTP-код ответа локального сервиса | HTTP 200; событие в инспекторе с пометкой об ошибке доставки |
| forward_remote | HTTP-код ответа удалённого HTTPS-сервиса (безопасные заголовки ответа могут быть переданы провайдеру) | HTTP 200; событие в инспекторе с пометкой об ошибке доставки |
При delivery_paused: true пересылка не выполняется; провайдер получает HTTP 200, событие сохраняется в инспекторе.
Если возможность webhook-inbox снята с тарифа владельца, публичный URL возвращает 404 Not Found.
События помечаются в инспекторе тегом webhook-inbox. Подробнее о просмотре — в документации инспектора HTTP-трафика.
---
Дашборд
На странице /dashboard/webhook-inbox (видна при наличии возможности webhook-inbox):
- Создать inbox — выбор режима и полей назначения;
- Копировать / открыть
public_url;
- Пауза доставки / Возобновить доставку.
- Удалить endpoint — выбрать endpoint, подтвердить необратимое удаление и получить подтверждение об успехе.
Подписи режимов в интерфейсе: Только хранение, Локальная пересылка, HTTPS пересылка.
Ошибки
401 Unauthorized
Когда: запрос к /api/webhook-inboxes без действующей сессии или с недействительными учётными данными.
Что делать: войдите в личный кабинет или передайте корректную авторизацию, как для остальных API дашборда.
---
403 Forbidden — заблокированный аккаунт
Когда: попытка создать inbox при заблокированном аккаунте (POST /api/webhook-inboxes).
Тело ответа (JSON): code: "user_suspended", сообщение «Аккаунт заблокирован».
Что делать: обратитесь в поддержку для разблокировки аккаунта.
---
403 Forbidden — нет возможности на тарифе
Когда:
- создание или изменение inbox без возможности
webhook-inbox на тарифе;
- создание или переключение в режим
forward_remote без опции webhook-inbox-remote-forward;
- превышена квота
max_webhook_inboxes при создании нового inbox.
Текст ответа: содержит forbidden и имя недоступной возможности или квоты (например feature webhook-inbox, feature webhook-inbox-remote-forward, quota max_webhook_inboxes).
Что делать: проверьте тариф и лимиты в разделе оплаты или обновите план. Удалите неиспользуемый inbox, если исчерпана квота количества.
---
400 Bad Request — некорректное тело
Когда: JSON в теле запроса не разбирается.
Текст ответа: invalid body.
Что делать: проверьте синтаксис JSON и заголовок Content-Type: application/json.
---
400 Bad Request — обязательный параметр
Когда: PATCH /api/webhook-inboxes без query-параметра id.
Текст ответа: id required.
Что делать: добавьте ?id=<tunnel_id> к URL.
---
400 Bad Request — недопустимый режим
Когда: в mode передано значение вне списка store_only, forward_local, forward_remote.
Текст ответа: invalid webhook inbox mode.
Что делать: используйте одно из допустимых значений режима.
---
400 Bad Request — недопустимый URL удалённой пересылки
Когда: для forward_remote указан URL не по HTTPS, адрес localhost, частной сети или иной запрещённый адрес.
Текст ответа: invalid remote forward URL.
Что делать: укажите публичный HTTPS-URL без частных IP и localhost. Если hostname указывает на частный адрес при фактическом соединении, доставка будет заблокирована; провайдер получит HTTP 200, а ошибка отобразится в инспекторе.
---
404 Not Found — inbox не найден
Когда:
PATCH для чужого или несуществующего tunnel_id;
- внешний запрос на
public_url inbox, если возможность webhook-inbox снята с тарифа владельца или запись inbox отсутствует.
Текст ответа (API): not found.
Что делать: проверьте tunnel_id и владельца inbox. Для публичного URL убедитесь, что inbox активен и тариф владельца включает функцию.
---
405 Method Not Allowed
Когда: на /api/webhook-inboxes вызван метод, отличный от GET, POST, PATCH (например DELETE).
Что делать: не отправляйте DELETE /api/webhook-inboxes: этот метод не поддерживается. Чтобы удалить endpoint, выберите его на /dashboard/webhook-inbox, нажмите Удалить endpoint и подтвердите действие. Для интеграции используйте общий API жизненного цикла туннелей: DELETE /api/tunnels?id=<tunnel_id>.
---
500 Internal Server Error / 503 Service Unavailable
Когда: внутренняя ошибка сервиса при создании, обновлении или чтении списка; сервис временно недоступен.
Что делать: повторите запрос позже. Если ошибка сохраняется — обратитесь в поддержку.
---
Ошибки доставки (видны в инспекторе, не в HTTP-ответе провайдеру)
Когда: пересылка на локальный клиент или удалённый HTTPS-эндпоинт не удалась (клиент отключён, сеть, таймаут, отказ upstream, отсутствие опции удалённой пересылки после смены тарифа, пауза доставки с пересылкой и т.д.).
Поведение для провайдера: HTTP 200 (подтверждение приёма), чтобы провайдер не повторял отправку бесконечно.
Поведение для вас: событие в инспекторе HTTP-трафика с тегами webhook-inbox и при необходимости delivery_error или capture_error; в заметках события — текст причины (например «локальный клиент не подключён»).
Что делать: проверьте подключение клиента, URL назначения, опцию тарифа, снимите паузу доставки; при необходимости повторите обработку через Replay.
Ограничения
- Подтверждение провайдеру при сбое доставки. В режимах с пересылкой при недоступности назначения, паузе доставки или отсутствии опции удалённой пересылки внешний провайдер всё равно получает HTTP 200. Это сделано намеренно, чтобы остановить повторные отправки со стороны провайдера. Факт сбоя смотрите в инспекторе трафика.
- Режим «только хранение». Провайдер всегда получает HTTP 200 с пустым телом; код ответа вашего приложения не формируется.
- Локальная пересылка требует клиента. Без подключённого клиента туннеля запрос сохраняется в инспекторе, пересылка не выполняется, провайдер получает HTTP 200.
- Удалённая пересылка — только HTTPS. HTTP-URL, localhost, частные и служебные адреса отклоняются при настройке; hostname, резолвящийся в частный IP при соединении, блокируется при доставке.
- Опция удалённой пересылки. Режим
forward_remote и поле remote_forward_url доступны только с опцией тарифа webhook-inbox-remote-forward. После снятия опции существующий inbox в этом режиме продолжает принимать вебхуки, но пересылка не выполняется до восстановления опции или смены режима.
- Квота количества inbox. Лимит
max_webhook_inboxes задаётся тарифом (на бесплатном плане по умолчанию — один inbox). Превышение блокирует только создание новых; существующие продолжают работать.
- Публичный URL неизменен. Смена режима, адреса назначения или паузы не меняет выданный
public_url; провайдеру не нужно обновлять endpoint.
- Удаление необратимо. Endpoint можно удалить в
/dashboard/webhook-inbox: выберите его, нажмите Удалить endpoint и подтвердите действие. После этого endpoint исчезает из списка, а его публичный URL навсегда перестаёт принимать webhook-запросы. Для интеграций доступен общий API жизненного цикла туннелей DELETE /api/tunnels?id=<tunnel_id>; отдельный DELETE /api/webhook-inboxes не поддерживается.
- Трафик inbox и лимиты тарифа. Входящие запросы на публичный URL inbox не расходуют те же лимиты HTTP RPM и исходящего трафика, что обычный прокси-туннель; это не отменяет общие правила тарифа для остального трафика аккаунта.
- Гостевые и закрытые туннели. Публичный URL inbox доступен внешним провайдерам без входа на платформу и не блокируется теми же правилами гостевого доступа, что приватные туннели.
- Захват в инспекторе. Размер и полнота тела запроса зависят от настроек инспектора HTTP-трафика и тарифа; при ошибке подготовки захвата провайдер всё равно получает HTTP 200, в событии может быть тег
capture_error.
- Заголовки при удалённой пересылке. На внешний HTTPS-эндпоинт не пересылаются служебные hop-by-hop заголовки; в ответ провайдеру из upstream передаётся ограниченный набор безопасных заголовков.
- Снятие возможности с тарифа. Если у владельца inbox больше нет
webhook-inbox, публичный URL отвечает 404 Not Found; API создания и изменения также возвращает отказ.
- Панель дашборда. Секция Webhook inbox скрыта, если возможность
webhook-inbox недоступна на тарифе, даже если старые записи существуют в системе.
Endpoint setup and health
Общее описание функционала
Дополнение «Настройка и состояние endpoint» расширяет облачный webhook inbox инструментами для быстрого создания endpoint, диагностики доставки и пошаговой настройки у провайдера. Доступно на тарифах с возможностью webhook-inbox вместе с родительской функцией; отдельной опции тарифа для дополнения нет.
В личном кабинете, в секции Webhook endpoints, доступны два сценария создания. Создать endpoint выдаёт публичный адрес и позволяет при необходимости указать название, описание и путь. Отдельная возможность Подключить localhost, когда она доступна, настраивает пересылку в локальное приложение через клиент туннеля. После создания отображаются сведения о назначении, публичном webhook URL, состоянии туннеля и последней активности.
Панель Состояние endpoint показывает назначение, локальный URL (для локальной пересылки), метку статуса и кнопки Проверить соединение и Тестовый POST. Чеклист настройки — десять универсальных шагов (без привязки к одному провайдеру) с счётчиком прогресса; отметки сохраняются в браузере для каждого endpoint.
Статусы endpoint в списке и в панели здоровья сопоставляются с полем API endpoint_status и отображаются на русском: Активен, Запуск, Ожидание локального клиента, Локальный сервер недоступен, Назначение не отвечает, Остановлен, Истёк, Ограничен планом.
Как пользователь может использовать
- Разработчик нажимает Создать endpoint, оставляет необязательные поля без изменений и сразу отправляет пробные вебхуки в инспектор.
- Интегратор через то же действие задаёт название, описание и путь (например
/webhooks/stripe), копирует полный public_webhook_url из чеклиста и вставляет в кабинет провайдера.
- Команда с локальным приложением создаёт endpoint через Подключить localhost, указывает
127.0.0.1:3000, подключает клиент туннеля и следит за статусом Ожидание локального клиента → Активен.
- Пользователь открывает панель Состояние endpoint, запускает Проверить соединение и видит, доступен ли публичный URL и (для локальной пересылки) подключён ли клиент и слушает ли порт приложения.
- QA нажимает Тестовый POST, чтобы отправить пробный POST на публичный URL и убедиться, что ingress принимает тело (событие может появиться в инспекторе).
- Оператор проходит Чеклист настройки (10 шагов), отмечает выполненные пункты и по кнопке Открыть инспектор переходит к просмотру входящих событий.
- Владелец аккаунта создаёт inbox через API с полем
create_intent (test_url, connect_localhost, webhook_endpoint) и читает обогащённый ответ с destination, public_webhook_url и endpoint_status.
- Пользователь ставит доставку на паузу и видит статус Остановлен в списке и в деталях.
- Пользователь с истёкшим по плану endpoint видит Истёк и поле
expires_at в API.
- При снятии возможности
webhook-inbox с тарифа статус Ограничен планом подсказывает, что функция недоступна на текущем плане.
Как это реализовано в сервисе
1. Вы создаёте endpoint в дашборде (один из трёх сценариев) или через POST /api/webhook-inboxes с create_intent. Сервис подбирает режим доставки (только хранение или локальная пересылка), выдаёт публичный базовый URL и при необходимости сохраняет имя, описание и путь webhook.
2. При запросе детали (GET /api/webhook-inboxes?id=) или списка сервис объединяет настройки inbox с состоянием туннеля: назначение, полный публичный webhook URL, срок действия, последняя активность, признаки подключения клиента и доступности локального порта, а также вычисленный endpoint_status.
3. Проверка соединения (POST /api/webhook-inboxes/connection-check) выполняет диагностику: для локальной пересылки — проверяет сессию клиента и TCP-доступность целевого адреса; для всех режимов — пробный HTTP-запрос к публичному webhook URL (HEAD по умолчанию; POST при test_request=true). Результат возвращается структурированно; статус endpoint пересчитывается по итогам проверки.
4. Интерфейс отображает те же поля, что API: бейджи статуса, панель здоровья и чеклист. Прогресс чеклиста хранится только в браузере пользователя и не синхронизируется между устройствами.
5. Базовое поведение приёма и пересылки вебхуков описано в документации webhook inbox. Контракт полей и проверки — в справочнике API. Ошибки — в справочнике ошибок. Ограничения — в известных ограничениях.
Обзор
Дополнение «Настройка и состояние endpoint» расширяет REST API webhook inbox обогащёнными полями в ответах, сценариями создания через create_intent, детальным чтением одного inbox и проверкой соединения. Все методы требуют авторизованной сессии, как и остальные вызовы /api/webhook-inboxes.
| Метод | Путь | Назначение |
| --- | --- | --- |
| GET | /api/webhook-inboxes?id=<tunnel_id> | Деталь одного inbox с полями состояния endpoint |
| POST | /api/webhook-inboxes/connection-check?id=<tunnel_id> | Диагностика локального и публичного соединения |
| POST | /api/webhook-inboxes | Создание с опциональным create_intent и метаданными |
Список GET /api/webhook-inboxes (без id) возвращает те же обогащённые поля в каждом элементе массива inboxes, что и детальный ответ.
---
Обогащённые поля inbox
Помимо полей базового webhook inbox, в ответах детали и списка могут присутствовать:
| Поле | Тип | Описание |
| --- | --- | --- |
| name | строка | Отображаемое имя endpoint (по умолчанию — хост публичного URL) |
| description | строка | Краткое описание (для сценария webhook_endpoint) |
| webhook_path | строка | Путь webhook относительно public_url, по умолчанию / |
| create_intent | строка | Сценарий создания: test_url, connect_localhost, webhook_endpoint |
| destination | строка | Человекочитаемое назначение: Cloud storage only (только хранение), адрес host:port (локальная пересылка) или HTTPS-URL (удалённая пересылка) |
| local_url | строка | http://… для локального адреса; пусто для режима только хранения |
| public_webhook_url | строка | Полный публичный URL с учётом webhook_path |
| endpoint_status | строка | Состояние endpoint (см. список ниже) |
| tunnel_status | строка | Состояние туннеля (например активен, на паузе, истёк) |
| client_connected | boolean | Подключён ли клиент туннеля (актуально для forward_local) |
| target_reachable | boolean | Принимает ли TCP-соединения локальный адрес назначения |
| expires_at | строка (RFC3339) | Срок действия endpoint по тарифу, если задан |
| last_activity_at | строка (RFC3339) | Время последней активности туннеля |
Значения endpoint_status
| Значение API | Подпись в дашборде |
| --- | --- |
| active | Активен |
| starting | Запуск |
| waiting_for_local_connection | Ожидание локального клиента |
| local_server_unavailable | Локальный сервер недоступен |
| destination_not_responding | Назначение не отвечает |
| stopped | Остановлен |
| expired | Истёк |
| limited_by_plan | Ограничен планом |
---
GET /api/webhook-inboxes?id=<tunnel_id>
Возвращает один обогащённый объект inbox для tunnel_id, принадлежащего текущему пользователю.
Query
| Параметр | Обязательность | Описание |
| --- | --- | --- |
| id | обязателен | Идентификатор inbox (tunnel_id) |
Успешный ответ 200
Тело — объект inbox со всеми полями из списка выше и базовыми полями (tunnel_id, public_url, mode, delivery_paused, created_at, updated_at и т.д.).
---
POST /api/webhook-inboxes
Создаёт inbox. Поведение базового API сохраняется; дополнение добавляет сценарии через create_intent и метаданные.
Дополнительные поля тела (JSON)
| Поле | Обязательность | Описание |
| --- | --- | --- |
| create_intent | необязательно | Сценарий создания (см. ниже). Если не указан, эквивалентен webhook_endpoint для режима только хранения |
| name | необязательно | Имя endpoint (имеет смысл при webhook_endpoint) |
| description | необязательно | Краткое описание |
| webhook_path | необязательно | Путь webhook, например /webhooks/stripe. Для test_url и connect_localhost обычно не задаётся — используется / |
Поля mode, target_addr, remote_forward_url по-прежнему можно передать явно; при указании create_intent режим выводится из сценария.
Сценарии create_intent
| Значение | Режим доставки | Поведение |
| --- | --- | --- |
| test_url | store_only | Публичный URL без локального сервера; путь по умолчанию / |
| connect_localhost | forward_local | Требуется target_addr (например 127.0.0.1:3000); пересылка через клиент туннеля |
| webhook_endpoint | store_only | Сохраняются name, description, webhook_path; полный URL = public_url + путь |
Успешный ответ 201 Created
Тело — обогащённый объект inbox (те же поля, что у GET с id), включая create_intent, public_webhook_url и endpoint_status.
---
POST /api/webhook-inboxes/connection-check?id=<tunnel_id>
Выполняет диагностику соединения для указанного inbox. Тело запроса пустое ({}).
Query
| Параметр | Обязательность | Описание |
| --- | --- | --- |
| id | обязателен | tunnel_id inbox |
| test_request | необязательно | true — публичная проверка выполняется методом POST вместо HEAD; в ответе optional_test_sent: true |
Другие HTTP-методы на этом пути возвращают 405 Method Not Allowed.
Успешный ответ 200
| Поле | Тип | Описание |
| --- | --- | --- |
| checked_at | строка (RFC3339) | Время проверки |
| endpoint_status | строка | Статус после проверки (список выше) |
| last_activity_at | строка (RFC3339) | Последняя активность туннеля, если известна |
| optional_test_sent | boolean | true, если выполнялся POST (test_request=true) |
| local | объект | Результат локальной диагностики |
| public | объект | Результат проверки публичного webhook URL |
Объект local:
| Поле | Описание |
| --- | --- |
| applicable | true для режима forward_local; иначе false и остальные поля неактуальны |
| client_connected | Подключён ли клиент туннеля |
| target_reachable | Доступен ли TCP на target_addr |
| target_addr | Проверяемый адрес |
| message | Пояснение при проблеме (например клиент не подключён, порт не слушает) |
Объект public:
| Поле | Описание |
| --- | --- |
| checked | Выполнялась ли проверка публичного URL |
| reachable | true, если HTTP-ответ успешен (код 1–499) |
| status_code | Код HTTP-ответа пробы |
| url | Проверяемый public_webhook_url |
| message | Пояснение при ошибке сети или статусе ≥500 |
---
Дашборд
На странице Туннели, секция Webhook endpoints:
- кнопки Тестовый URL, Подключить localhost, Webhook endpoint — соответствуют
create_intent;
- в списке — бейдж статуса по
endpoint_status;
- при выборе inbox — Состояние endpoint, Чеклист настройки (10 шагов, счётчик
N/10).
Подробнее о сценариях использования — в описании дополнения.
401 Unauthorized
Когда: вызов GET /api/webhook-inboxes?id=…, POST /api/webhook-inboxes/connection-check или создание с create_intent без действующей сессии.
Что делать: войдите в личный кабинет или передайте корректную авторизацию, как для остальных API дашборда.
---
400 Bad Request — не указан идентификатор inbox
Когда:
GET /api/webhook-inboxes с единственной целью получить деталь, но без query-параметра id (для детали параметр обязателен);
POST /api/webhook-inboxes/connection-check без id в query.
Текст ответа: сообщение о том, что требуется идентификатор туннеля (id required).
Что делать: добавьте ?id=<tunnel_id> к URL.
---
400 Bad Request — недопустимый сценарий создания
Когда: в теле POST /api/webhook-inboxes передано неизвестное значение create_intent (не test_url, connect_localhost, webhook_endpoint).
Текст ответа: указывает на недопустимый сценарий создания (invalid create intent).
Что делать: используйте одно из трёх допустимых значений или опустите поле и задайте mode вручную по базовому API webhook inbox.
---
400 Bad Request — некорректное тело
Когда: JSON в теле запроса не разбирается.
Текст ответа: invalid body.
Что делать: проверьте синтаксис JSON и заголовок Content-Type: application/json.
---
405 Method Not Allowed — проверка соединения
Когда: на /api/webhook-inboxes/connection-check вызван метод, отличный от POST (например GET).
Что делать: используйте только POST с параметром id в query.
---
403 Forbidden — нет возможности или квоты
Когда: создание inbox без возможности webhook-inbox на тарифе или превышена квота max_webhook_inboxes.
Что делать: см. справочник ошибок webhook inbox. В деталях существующего inbox endpoint_status может быть limited_by_plan (Ограничен планом).
---
404 Not Found — inbox не найден
Когда: GET с id, connection-check или PATCH для чужого или несуществующего tunnel_id.
Текст ответа (API): not found.
Что делать: проверьте tunnel_id и владельца inbox.
---
500 Internal Server Error / 503 Service Unavailable
Когда: внутренняя ошибка при чтении детали, проверке соединения или создании с create_intent; сервис временно недоступен.
Что делать: повторите запрос позже. Если ошибка сохраняется — обратитесь в поддержку.
---
Диагностика без отдельного HTTP-кода ошибки
Когда: POST /api/webhook-inboxes/connection-check завершился с HTTP 200, но в теле public.reachable: false или local.client_connected: false.
Поведение: это не сбой API — сервис вернул результат проверки. Поле endpoint_status отражает выявленное состояние (например waiting_for_local_connection, local_server_unavailable, destination_not_responding).
Что делать: следуйте подсказкам в local.message и public.message; подключите клиент туннеля, запустите локальное приложение, проверьте публичный URL и настройки провайдера. Подробнее — в известных ограничениях.
---
Ошибки базового webhook inbox
Создание без create_intent, смена режима, пауза доставки и публичный приём вебхуков используют те же коды, что родительская функция — см. справочник ошибок webhook inbox.
Ограничения
- Сценарий
create_intent только при создании. Поле create_intent задаётся в POST /api/webhook-inboxes и сохраняется для отображения; сменить сценарий после создания нельзя — используйте PATCH для режима, адреса и метаданных по базовому API.
- Статус «Запуск». В течение примерно 30 секунд после создания
forward_local inbox без подключённого клиента API и дашборд могут показывать starting (Запуск) вместо Ожидание локального клиента.
- Проверка соединения — моментальный снимок. Результат
connection-check отражает состояние на момент запроса; TCP-проба локального порта кратковременна, публичная проба — HTTP HEAD или POST с сервиса. Сеть провайдера и ваш браузер могут видеть URL иначе, чем внутренняя проверка.
- Публичная проба с платформы. Доступность
public_webhook_url проверяется запросом от инфраструктуры сервиса. Локальные или корпоративные ограничения на стороне провайдера эта проверка не моделирует.
- Тестовый POST. Кнопка Тестовый POST и параметр
test_request=true отправляют пустой POST с заголовком Content-Type: application/json. Для inbox в режиме только хранения событие может появиться в инспекторе; на локальную пересылку влияет только если клиент и приложение готовы принять трафик.
- Поле
destination в API на английском. Значения вроде Cloud storage only приходят в JSON API; в дашборде те же смыслы показаны в полях Назначение на русском или в виде адреса.
- Чеклист только в браузере. Прогресс Чеклист настройки (10 шагов, счётчик
N/10) хранится в localStorage отдельно для каждого tunnel_id и браузера; другие устройства и пользователи его не видят; очистка данных сайта сбрасывает отметки.
- Чеклист не влияет на доставку. Отметки шагов информационные; они не меняют настройки inbox, туннеля или провайдера.
- Статус при удалённой пересылке.
destination_not_responding (Назначение не отвечает) выставляется после проверки соединения или обогащения детали, когда удалённый HTTPS-назначение недоступно; для режима только хранения этот статус не применяется.
- Список и деталь. Обогащённые поля (
endpoint_status, public_webhook_url и др.) включены в список и в GET с id; для автоматизации удобнее детальный запрос, если нужны все поля одного endpoint.
- Родительские ограничения. Квоты inbox, пауза доставки, поведение при сбое пересылки, лимиты инспектора и тарифные опции удалённой пересылки описаны в известных ограничениях webhook inbox.
Mock endpoint responses
Общее описание функционала
Аддон mock-ответов превращает облачный webhook inbox в управляемый mock-эндпоинт. Вы задаёте HTTP-статус, безопасные заголовки, тело и задержку — провайдер получает этот ответ без локального приложения. Каждый входящий запрос по-прежнему пишется в журнал трафика с пометками mock-правила или fallback.
Режим mock взаимоисключающ с хранением без доставки и с локальной/удалённой пересылкой. Правила и fallback сохраняются при смене режима.
Как пользователь может использовать
1. Включите webhook inbox и аддон mock на подходящем тарифе.
2. В карточке inbox переключите режим доставки на Mock (остальные режимы отключатся).
3. Задайте fallback (по умолчанию 200 с пустым телом) и добавьте правила: метод, точный или префиксный путь, ответ, опционально лимит использований и задержку до 10 с.
4. Примените готовый пресет (200/202/400/401/403/404/409/429/500/503) или соберите ответ вручную.
5. Отправьте webhook на публичный URL inbox — получите сконфигурированный ответ; в журнале появится событие с тегами mock.
6. При паузе доставки провайдер получает обычный ACK; правила не расходуются, событие помечается как paused, не как ошибка доставки.
Как это реализовано в сервисе
Публичный запрос к inbox в режиме mock проходит через оценку упорядоченных правил (приоритет, затем стабильный id). Первое подходящее неистекшее правило отдаёт ответ после задержки; при исчерпании использований сервис сразу переходит к следующему правилу или fallback без ожидания задержки исчерпанного правила. Ограниченные использования списываются атомарно после успешной задержки. Ответ и метаданные попадают в журнал; сбой подготовки захвата тела не меняет уже выбранный HTTP-ответ провайдеру. Ручная отправка тестового события в mock-inbox использует ту же оценку правил.
API — mock-ответы webhook inbox
Базовый путь: /api/webhook-mocks (сессия пользователя; CSRF на изменяющих методах).
| Метод | Путь | Назначение |
| --- | --- | --- |
| GET | /settings?tunnel_id= | Fallback, version, rule_count |
| PUT/PATCH | /settings | Обновить fallback с version |
| GET | /rules?tunnel_id= | Список правил |
| POST | /rules | Создать правило (preset или полный response) |
| PATCH | /rules/<id> | Обновить правило |
| DELETE | /rules/<id>?tunnel_id= | Удалить |
| POST | /rules/reorder | Транзакционный reorder + version |
Переключение режима: PATCH /api/webhook-inboxes?id= с mode: "mock" (нужны и parent inbox, и аддон mock).
Поля ответа правила/fallback: status, headers[] (name/value), тело в base64, delay_ms. Небезопасные имена заголовков (в том числе Set-Cookie, Location) отклоняются на сохранении.
Ошибки — mock-ответы webhook inbox
| HTTP | code | Когда | Что делать |
| --- | --- | --- | --- |
| 400 | invalid_request | Невалидные поля, небезопасные заголовки | Исправьте поля и повторите |
| 401 | unauthorized | Нет аутентификации | Войдите снова |
| 403 | feature_disabled | Нет webhook inbox или аддона mock | Смените тариф или дождитесь включения |
| 403 | user_suspended | Аккаунт приостановлен | Обратитесь в поддержку |
| 404 | not_found | Чужой/отсутствующий endpoint или правило | Проверьте id и владельца |
| 409 | stale_version | Устаревшая version | Перечитайте настройки и сохраните снова |
| 409 | reorder_conflict | Конфликт приоритетов при reorder | Перечитайте список правил и повторите |
| 409 | rule_quota | Больше 100 правил | Удалите лишние правила |
| 413 | body_too_large | Тело больше лимита тарифа/приложения | Уменьшите тело или включите захват тела |
| 429 | delay_concurrency | Слишком много отложенных ответов | Подождите и повторите |
| 429 | rate_limited | Превышен RPM | Снизьте частоту запросов |
| 500 | — | Неожиданная ошибка | Повторите позже или обратитесь в поддержку |
Ограничения — mock-ответы webhook inbox
- Нет цепочки «mock, затем forward», regex/glob путей, скриптов и сетевого chaos (TCP reset, streaming).
- Задержка ответа не больше 10 секунд.
- Размер тела ответа не больше минимума из 256 КиБ и лимита захвата тела вашего тарифа; без права на захват тела допускается только пустое тело.
- Не больше 100 правил на один endpoint.
- Сопоставление пути: только exact или prefix; пустые условия = match-all.
- В ответе нельзя задавать служебные заголовки вроде Content-Length, hop-by-hop, а также Set-Cookie и Location.
- Аддон доступен на платных планах с webhook inbox; на Free mock по умолчанию закрыт.
- Одновременно удерживается ограниченное число отложенных mock-ответов на владельца (лишние получают 429).