Зачем держать больше одного способа оплаты
Каскад — это правило «если первый способ не сработал, предложи второй, не создавая новый заказ». Никакой магии: вы просто не отпускаете покупателя после первого отказа. Отдача заметная — часть людей, которые упёрлись в отказ банка, платят со второй попытки другим методом.
Причин для отказа много, и почти все они не про вас. У покупателя не подключён СБП в его банке, лимит переводов исчерпан, приложение банка не установлено на этом устройстве, платёж по карте не прошёл 3-D Secure. В каждом из этих случаев человек готов заплатить — ему просто нужен другой путь.
Второй мотив — устойчивость. Если у одного метода технические проблемы, проект с двумя методами теряет часть конверсии, а проект с одним методом останавливает продажи целиком. Для магазина цифровых товаров с выручкой в выходные это разница между «просели» и «день выпал».
Один заказ, несколько попыток: как это выглядит в базе
Главная ошибка каскада — путать заказ и попытку оплаты. Это две разные сущности, и их нужно развести в модели данных до того, как вы напишете первую строчку кода.
| Заказ | Попытка оплаты | |
|---|---|---|
| Сколько на покупку | ровно один | сколько угодно |
| Ключ | order_id | payment_id |
| Что хранит | кто, что и на сколько купил | метод, статус, время жизни ссылки |
| Когда закрывается | когда любая попытка дала paid | по paid, canceled или expired |
В RollyPay идемпотентность создания платежа завязана на order_id. Это значит: если вы хотите вторую полноценную попытку с другим методом, у неё должен быть свой идентификатор — например ORD-1042-try2, где ORD-1042 остаётся в вашей таблице заказов как родитель. Тогда обе попытки видны в отчётах, а заказ по-прежнему один.
Практика, которая экономит нервы: заведите таблицу payment_attempts с полями order_id, payment_id, method, status, created_at. Выдачу товара привязывайте к заказу, а не к попытке — тогда даже две одновременно оплаченные попытки не превратятся в две отгрузки.
Что показать покупателю после отказа
Человек, у которого не прошла оплата, находится в худшей точке всей воронки. Ему нужно понять две вещи за три секунды: деньги не списались и что нажать дальше.
- Скажите про деньги первым делом. «Оплата не прошла, деньги не списались» — эта фраза снимает главный страх.
- Дайте одну кнопку. «Оплатить картой» под текстом об отказе СБП. Не список из четырёх вариантов.
- Сохраните сумму и товар на экране. Возвращать человека в корзину заново — почти гарантированная потеря.
- Не пересказывайте код ошибки банка. «Ошибка 05» не помогает никому.
Отдельно про причину отказа. Прятать её полностью — плохо: покупатель решит, что сломался ваш сайт. Но и подробности вроде «превышен лимит операций» вы часто не знаете точно. Рабочая середина: «Банк отклонил платёж. Так бывает из-за лимитов или настроек приложения — попробуйте другой способ». Честно и без выдумок.
Кнопка «попробовать снова тем же способом» тоже нужна: часть отказов разовые, и повтор через минуту проходит.
Чего нельзя делать: платёж на каждый клик
Самая частая поломка — создавать новый платёж по каждому нажатию кнопки. Покупатель нервничает, кликает пять раз, у вас в базе пять активных ссылок на одну покупку. Дальше начинается интересное.
- Двойная оплата. Человек открыл две вкладки и оплатил обе. Вы получаете два
payment.paidи должны один из них вернуть. - Мусор в отчётах. Конверсия рушится: знаменатель раздут отменёнными попытками, а вы гадаете, почему всё плохо.
- Битые уведомления. Колбэки приходят по всем пяти платежам, и обработчик выдаёт товар столько раз, сколько увидел
paid.
Лечится тремя правилами. Первое: кнопка блокируется на время запроса. Второе: если у заказа уже есть попытка в статусе created или processing, отдавайте её pay_url, а не создавайте новую. Третье: обработчик колбэка проверяет, не выдан ли товар по этому заказу, — и если выдан, просто отвечает 2xx и ничего не делает.
Помните и про время жизни ссылки: в ответе на создание платежа есть expires_at. Пока он не наступил, старую ссылку можно и нужно переиспользовать. Новую попытку заводите, когда прилетело payment.canceled или payment.expired, — тогда каскад работает по факту, а не по клику мышью.
Что мерить, чтобы понять, работает ли каскад
Одной цифры «конверсия» здесь мало — она смешивает разные вещи. Считайте три.
| Метрика | Как считать | Зачем |
|---|---|---|
| Конверсия попытки | оплаченные попытки / все попытки | показывает качество конкретного метода |
| Конверсия заказа | оплаченные заказы / все заказы | честный ответ, сколько денег вы собрали |
| Доля вторых попыток | заказы с двумя и более попытками / все заказы | говорит, стоит ли каскад усилий |
| Спасённые заказы | оплата со второй попытки другим методом | прямая выручка от каскада |
Пример из практики: SaaS с подпиской на 1 490 ₽ видел конверсию заказа 71%. После добавления второго метода на экран отказа доля вторых попыток составила около 12% заказов, из них оплатили примерно половину — конверсия заказа выросла до 77%, при этом конверсия попытки формально упала. Смотреть надо на заказы.
Когда каскад не нужен
Если у вас 20 продаж в месяц, разница между 71% и 77% — это один заказ. Потратить неделю на маршрутизацию ради него не стоит: соберите базовую оплату по платёжной ссылке и займитесь трафиком.
Каскад также бесполезен, когда отказы вызваны не методом, а модерацией или настройками кассы: пока категория проекта и доступные методы не подтверждены, второй способ будет отказывать так же, как первый. И он лишний, если у вас честно доступен один метод — тогда лучше вложиться в то, чтобы форма оплаты не теряла людей на телефоне. Когда объёмы дорастут, включить приём платежей на сайте с двумя методами можно за вечер — модель данных к тому времени уже будет правильной.