Автоматизация продления подписок: Telegram-клуб без ручной паники

Автоматизация продления подписок в Telegram-клубе — это связка биллинга, календаря paid_until, напоминаний за 7/3/1 день, проверки failed invoices и ручного handoff только там, где деньги уже почти дошли. 16 июля 2026 в утреннем отчёте Solar OS всплыл простой сигнал: одна месячная подписка истекла 9 июля, а очередь неоплаченных счетов накопила 4 позиции. Такая сцена полезнее абстрактного разговора про retention: система показывает, где именно течёт выручка.

Для малого SaaS, закрытого клуба, платного Telegram-канала или сервиса с помесячной оплатой продление нельзя держать в голове владельца. Нужна операционная петля: бот создаёт счёт, хранит срок доступа, заранее напоминает, после просрочки переводит клиента в winback-сценарий, а менеджеру отдаёт только тёплые случаи. Если этот контур не собрать, бизнес видит падение MRR уже после факта. Утро начинается с отчёта, а не с догадок.

Что считается продлением, а что является шумом

В подписочной модели есть 4 разных события: active subscription, pending invoice, failed invoice и expired access. Активная подписка даёт доступ. Pending invoice означает, что человек дошёл до оплаты, но деньги ещё не подтверждены. Failed invoice говорит о незавершённой оплате или техническом сбое. Expired access фиксирует момент, когда paid_until прошёл, а продления нет.

Если бот показывает только число активных пользователей, владелец видит витрину, а не механику. Для нормальной автоматизации каждое состояние должно быть машинно читаемым и иметь следующий шаг: отправить сообщение, закрыть старый счёт, обновить доступ, создать задачу Product, передать платёжный статус Finance или оставить событие в наблюдении.

Минимальная схема данных для подписочного бота

База продления начинается с таблицы subscriptions: user_id, username, tariff_code, amount, currency, status, activated_at, paid_until, expired_at, last_warning_at и source. Для платежей нужна таблица invoices: invoice_id, user_id, provider, provider_payment_id, status, created_at, paid_at, failed_at, expires_at, retry_count. Эти 2 таблицы закрывают большую часть бытового хаоса.

В Telegram-клубе дополнительно нужны chat_id, topic_id и access_state. Операция продления должна быть транзакционной на уровне бизнес-логики: платёж подтверждён, подписка обновлена, доступ выдан, audit row записан. Если один шаг не прошёл, система создаёт alert. Пользователь не должен видеть внутренний цирк; цирк остаётся в логах, где ему и место.

Как строится цепочка 7/3/1 и day-after

Календарь предупреждений лучше задавать событиями. Система каждый день берёт подписки, у которых paid_until попадает в окно, и проверяет, было ли уже отправлено предупреждение нужного типа. Для warn7 это paid_until минус 7 дней, для warn3 — минус 3 дня, для warn1 — минус 1 день. После отправки пишется subscription_event.

Day-after сценарий запускается на следующий день после истечения, если оплата не пришла. Его задача — не давить, а вернуть человека в понятный маршрут: показать, что доступ приостановлен, дать кнопку продления и коротко напомнить, что лежит внутри. Для клуба Solar это артефакты из реальной системы, код, промпты, AGENTS.md и рабочие разборы.

Как failed invoices превращаются в рабочую очередь

Очередь failed invoices нужна не для массовых касаний. Cold outbound закрыт, и это правильно. Очередь нужна для warm recovery: человек уже сам начал оплату, получил счёт, нажал кнопку, но процесс не завершился. Бот может показать повторную ссылку, Finance может сверить статус провайдера, Product может поправить UX.

Полезная строка в очереди выглядит так: username, tariff_code, amount, invoice_age_days, last_touch, provider_status, source, next_action. Если счёт висит 1 день, бот отправляет автоматический retry. Если 7 дней, событие уходит в Product. Если 14 или 30 дней, это аналитика намерения оплатить, а не пожар.

Какие метрики смотреть утром

Ежедневный отчёт подписочного продукта должен начинаться с 6 строк: active paid users, MRR или внутренняя регулярная выручка, expiring_next_7d, failed_invoices_count, pending_to_active за 7 дней и expired_without_cancel за 7 дней. Этого достаточно, чтобы понять, где горит, а где просто шум одного календарного окна.

Для публичных материалов внутренние MRR-цифры лучше не раскрывать. Для операционного отчёта внутри команды они обязательны. Клиентам и подписчикам показывают полезный артефакт, а не внутреннюю кассу Solar. В статье можно разобрать структуру отчёта, SQL-запросы, статусы и сценарии. Персональные данные пользователей остаются внутри.

Как связать бота, платёжку и задачи агентам

Практическая архитектура состоит из 5 компонентов. Первый — bot.py, который показывает тарифы и создаёт invoice. Второй — payment poller или webhook receiver, который подтверждает оплату через PaySame. Третий — expiry job, который проверяет paid_until. Четвёртый — reporting job. Пятый — task router, который создаёт задачи Product, Finance или Marketing.

Роутинг важнее красивого дашборда. Если warn3 не отправлялся, задача идёт Product. Если есть failed invoices старше 7 дней, задача идёт Finance или Sales по warm recovery. Если новых pending нет, задача идёт Marketing: посмотреть контент, CTA на клуб и источники входящих. Каждый получает свою часть, а не общий крик.

Чек-лист внедрения за одну неделю

1. paid_until. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

2. invoice idempotency. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

3. payment webhook. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

4. warning events. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

5. day-after. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

6. failed queue. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

7. access sync. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

8. report routing. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

9. privacy. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

10. approval gate. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

11. quiet hours. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

12. observability. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

13. test fixtures. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

14. content promise. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

15. operator summary. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

16. tariff source. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

17. provider status. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

18. retry policy. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

19. manual override. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

20. audit trail. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

21. topic access. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

22. billing copy. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

23. warm handoff. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

24. duplicate invoice. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

25. expired access. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

26. renewal UX. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

27. cron freshness. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

28. source attribution. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

29. dashboard row. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

30. postcheck window. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

31. incident class. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

32. owner field. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

33. Telegram errors. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

34. currency handling. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

35. quarter tariff. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

36. monthly tariff. Проверьте этот участок отдельным тестом, а не общим ощущением «работает». У пункта должны быть владелец, лог, дата последней проверки и понятный следующий шаг. Если проверка падает, система не должна молчать: она создаёт задачу, пишет причину и показывает, кто должен действовать. Такой скучный порядок спасает больше денег, чем красивый экран с графиками. Да, скучно. Зато не больно.

Итог: renewal flow — это продукт, а не бухгалтерская мелочь

Продление подписки — часть пользовательского опыта. Человек не обязан помнить, когда у него paid_until, где лежит ссылка, какой счёт был создан и почему банк показал ошибку. Это должна помнить система. Бот создаёт счёт, poller подтверждает оплату, expiry job ведёт календарь, daily report показывает риск, task router отдаёт работу нужному агенту. Владелец видит только управляемые сигналы: что истекает, что не оплачено, где нужен Product, где Finance, где Marketing.

Свежий разбор из Solar OS 16 июля 2026 показал не катастрофу, а рабочую механику: отчёт поймал истечение, отделил retention от acquisition, нашёл failed invoices и запустил задачи на recovery. Это нормальный уровень автоматизации малого подписочного продукта. Система не обещает вечный рост и не притворяется пророком. Она каждое утро кладёт на стол факты, а потом заставляет людей заниматься причиной, а не настроением.

У меня это всё крутится 24/7. Кому интересно как устроено внутри — клуб «Solar — внутрянка», от 2 500 ₽/мес. Бери и адаптируй: https://4bos.ru/inside/. Из близких разборов смотри также автоматизацию клиентского сервиса и стоп-краны в автоматизации бизнеса.

Solar OS.

Частые вопросы

Какие статусы нужны для подписочного бота?
Минимум 6 статусов: active, expiring_soon, invoice_pending, payment_failed, expired и winback. Active даёт доступ и входит в регулярную выручку. Invoice_pending показывает незавершённую оплату, payment_failed — технический или поведенческий сбой, expired — завершение paid_until без продления. Такая схема нужна Telegram-клубу, SaaS и закрытому сообществу, потому что каждый статус ведёт к разному действию.
Когда отправлять напоминания о продлении?
Практичный ритм — за 7, 3 и 1 день до paid_until, затем day-after сообщение после просрочки. Каждый тип напоминания должен записываться в subscription_events, чтобы cron можно было запускать повторно без дублей. В тексте достаточно даты, ссылки на оплату и короткого объяснения, что произойдёт с доступом.
Что делать с failed invoices?
Failed invoice нельзя сразу считать отказом. В первые 24 часа это часто сбой банка, забытая вкладка оплаты или повторный webhook платёжки. После 7 дней событие стоит отдавать Product или Finance: проверить UX, статус провайдера и корректное тёплое касание. Для массового cold outbound это не повод; человек уже сам начал оплату.
Какие метрики смотреть каждый день?
Достаточно 6 строк: active paid users, MRR или внутренняя регулярная выручка, expiring_next_7d, failed_invoices_count, pending_to_active за 7 дней и expired_without_cancel за 7 дней. Если pending нет, проблема ближе к acquisition. Если pending есть, но active не растёт, проверяют оплату и onboarding. Если растёт expired, чинят retention.

Читайте также

Подписаться на блог в Telegram

Читайте свежие кейсы об AI-автоматизации, системной архитектуре и масштабировании бизнеса.

Подписаться