Как тестировать вебхуки в ForTunnels
Платёж прошёл, а заказ остался неоплаченным. Где искать ошибку: платёжный сервис не отправил webhook, запрос потерялся по дороге или обработчик не понял его содержимое? Логи приложения помогут, если запрос до него дошёл.
Проверим это на ForTunnels: примем запрос в облачный Inbox, вернём отправителю ошибку, а затем подключим локальный обработчик через HTTP-туннель.
Сначала ловим запрос
В личном кабинете открываем «Inbox webhook» и нажимаем «Создать адрес». Вводим название, например «Хабр: тест оплаты», и путь /webhooks. Краткое описание можно оставить пустым. После создания адрес работает в режиме «Только хранение»: запросы принимает сам сервис, запускать локальное приложение или клиент туннеля пока не нужно.
Форма создания адреса. Все скриншоты сняты в локальной версии 2 октября 2026 года на демонстрационных данных.
В карточке есть полный URL и кнопка «Копировать». На скриншоте адрес локального стенда; для внешнего отправителя нужен HTTPS-URL из вашего кабинета.
Перед отправкой на вкладке «Состояние» находим кнопку «Открыть инспектор» под чеклистом настройки. В инспекторе переходим в «Настройки», включаем «Полный захват тел» и сохраняем изменение. Эта возможность должна быть доступна на тарифе. Без неё в журнале останутся метаданные, но посмотреть JSON не получится. Ручные тесты, mock-ответы и Replay тоже зависят от тарифа.
Первый запрос отправим через curl. В переменную вставляем скопированный URL целиком, вместе с /webhooks:
Inbox ответит 200 OK, а во вкладке «События» появится запись. Открываем её и сверяем метод, путь, Content-Type и тело запроса. Уже здесь можно заметить, что отправитель использует другой путь, передаёт форму вместо JSON или кладёт идентификатор заказа не в то поле, где его ищет обработчик.
Теперь указываем этот URL в тестовом окружении платёжного сервиса и вызываем тестовое событие уже оттуда. Запрос через curl проверил приём на нашей стороне; доставку от провайдера ещё предстоит проверить. Формат JSON у него будет свой.
Ответ 200 OK от Inbox означает, что сервис принял запрос. В режиме «Только хранение» он не меняет статус заказа и не выполняет нашу бизнес-логику. Это проверим позже, на своём обработчике.
Возвращаем 503 и проверяем повторную доставку
Вернёмся в карточку адреса. На вкладке «Доставка и mock» выбираем «Mock ответы» и нажимаем пресет 503 Unavailable. Появится включённое правило для всех запросов. Ниже находится «Fallback-ответ»: он применяется, когда ни одно правило не подошло.
Повторяем ту же команду curl. Теперь получаем 503 Service Unavailable с телом {"error":"unavailable"}. В инспекторе открываем новое событие и переключаем детали на «Ответ», чтобы увидеть статус и тело, которые получил отправитель.
Чтобы проверить автоматические повторы, снова вызываем тестовое событие у провайдера. Если он повторяет доставку после 503, в журнале появятся новые запросы. Сравниваем идентификаторы событий, содержимое и интервалы между попытками. Затем выключаем правило 503: при fallback со статусом 200 и отсутствии других подходящих правил Inbox начнёт отвечать успешно. Проверяем, прекратил ли отправитель повторы. Их расписание и условия зависят от провайдера; обычная команда curl из примера сама запрос не повторяет.
Для проверки таймаута можно задать задержку ответа, например 3000 мс. Если используем поле «Задержка, мс» в fallback, сначала выключаем правило для всех запросов, иначе fallback не сработает. В mock-режиме допустима задержка до 10 секунд. Успеет ли клиент дождаться ответа, зависит от его настроек.
Подключаем локальный обработчик
Допустим, обработчик уже запущен на localhost:8000/webhooks. Подключим его через обычный HTTP-туннель. Устанавливаем CLI, создаём токен в кабинете и сохраняем его в локальной конфигурации:
В настройках провайдера заменяем адрес Inbox на HTTPS-URL нового туннеля с путём /webhooks. Оставляем клиент запущенным. Теперь запрос дойдёт до локального приложения: можно поставить точку останова в обработчике и проследить, почему заказ не меняет статус.
Если обработчик вернул ошибку, исправляем код, открываем событие в инспекторе туннеля и нажимаем «Replay request». Запрос снова уйдёт на цель этого туннеля. Полностью сохранённое тело подставится автоматически; если оно отсутствует или обрезано, задаём его вручную. Учётные данные, cookies и служебные заголовки при повторе удаляются. Поэтому Replay подходит для отладки обработки запроса, а проверку подписи провайдера нужно учитывать отдельно.
Проверяем дубли и ошибки в данных
В деталях события есть кнопка «Сохранить как шаблон». Сохраняем запрос и открываем его во вкладке «Тест». На его основе можно подготовить варианты без order_id, с неизвестным типом события и с повторяющимся id.
Дубль особенно полезно проверить для платежей: два вызова с одним событием не должны дважды менять баланс или создавать две отгрузки. Одного ответа 200 здесь недостаточно. После повторной отправки смотрим, что произошло с заказом и записями в базе приложения.