Сервис для продавцов Авито молчал о своих деньгах. Научили его говорить первымМы делаем ИИ-агентов, которые ведут продажи за продавцов на Авито: отвечают покупателям, собирают карточки объявлений, следят, когда клиенту пора продлевать тариф. Обычный SaaS с подпиской через ЮKassa. Казалось бы — мелкий технический узел. Но именно он определяет, через сколько минут владелец сервиса узнаёт, что у него появились живые деньги.
Задача была простая: любой платёж клиента — переход на тариф, продление, разовая покупка, автосписание — должен долетать до владельца сразу, без похода в личный кабинет платёжной системы. Для сервиса с несколькими одновременными клиентами это не «было бы неплохо», а кислород: узнал поздно — поздно заметил сбой списания, поздно увидел, что тариф не включился.
Как нашли дыру
23 октября в 18:12 по Москве клиент оплатил тариф с ИИ-карточками для объявлений — 1111 ₽ через СБП. Платёж прошёл штатно, тариф включился. Но узнали об этом не из сервиса, а из личного кабинета банка — по другому поводу. Сервис молчал.
Разобрали код и нашли: уведомления о платеже не было вообще, ни в одном из каналов, которыми в сервис приходят деньги. Прошли по всем местам, где в коде вообще встречается слово «платёж» — вебхуки, ручки оформления подписки, фоновые задачи. Функции, которая писала бы владельцу «тебе заплатили», не существовало с момента запуска биллинга. А каналов четыре: вебхук ЮKassa, когда клиент платит картой или через СБП; три «мгновенных» эндпоинта без паузы на ожидание банка — переход на тариф, возврат из паузы, разовая покупка пакета ИИ-карточек; и ежедневный крон повторных списаний у подписчиков, который проводит настоящие деньги без участия человека в моменте оплаты. Четыре входа денег — и один слепой угол на все четыре.
Что сделали
Собрали один модуль, который слушает ровно эти четыре точки и для каждой формирует одно и то же: короткое сообщение в Telegram о том, что произошло, кому и на сколько. Вебхук, три эндпоинта и фоновая задача списаний теперь пишут в одну точку, а не молчат по отдельности.
Отдельно решили, куда это должно приходить — не «во все админские чаты на всякий случай», а туда, куда выбрал сам владелец: личный чат и рабочая группа команды, список адресатов отдельным файлом, без правки кода.
Единственная засада была внутри самого запуска. Модуль живёт в общем пакете сервиса, и без явного первого импорта всего пакета целиком тянет за собой круговую зависимость: на столе разработчика код проходит спокойно, а внутри боевого контейнера падает с ошибкой импорта, потому что там порядок загрузки модулей другой. Проверять пришлось сразу в контейнере, а не локально — иначе разница всплыла бы уже на проде.
Результат
С вечера 25 октября каждый платёж — через любой из четырёх путей — приходит владельцу текстом в Telegram за секунды, а не по факту случайной проверки банковского кабинета. Проверили на реальном рекуррентном списании и на разовой покупке: сообщение долетает раньше, чем клиент успевает написать в поддержку «я оплатил, а доступ не открылся». Рабочая группа видит те же сообщения — если владелец офлайн, оплату всё равно заметит кто-то из команды. Честная граница: модуль показывает, что деньги пришли, но не разбирает, почему конкретный тариф не включился при сбое на стороне платёжной системы, — это отдельная открытая задача.
Что забрать себе
Если в вашем сервисе деньги заходят больше чем одним путём — через вебхук платёжки, ручную выдачу доступа, фоновый крон списаний, — выпишите все эти пути отдельным списком и для каждого ответьте: кто и как узнает о событии в момент, когда оно случилось, а не на следующий день при сверке. Личный кабинет платёжной системы — это не система уведомлений, а шкаф с документами, в который нужно самому прийти и открыть ящик. Забыли прийти — деньги всё равно лежат там, просто никто об этом не знает, пока кто-то не проверит случайно, по другому поводу.