После перевыпуска банковской карты очередной автоплатеж может быть отклонен, хотя на счете есть деньги, подписка раньше продлевалась без ошибок, а пользователь не отменял согласие на списания. Причина не всегда находится в самой карте: сбой может возникнуть в сохраненном способе оплаты, настройке подписки, обработке статусов, повторных попытках или логике доступа после неуспешного платежа.
Система обновления карточных реквизитов у банков и платежных сетей иногда передает новые данные эквайеру автоматически, но полагаться на это как на гарантию нельзя. Результат зависит от банка-эмитента, платежной сети, провайдера, причины перевыпуска и согласия держателя карты. Если карта была потеряна или скомпрометирована, автоматическое обновление может быть намеренно запрещено. Поэтому у сервиса должен существовать понятный сценарий ручной замены способа оплаты.
Сначала определите, что именно перестало работать
Не начинайте с повторного списания наугад. Возьмите одну конкретную подписку и соберите цепочку событий: идентификатор клиента у платежного провайдера, идентификатор сохраненного payment method, счет или платеж, время попытки, итоговый статус, код отказа, webhook и состояние подписки в вашей базе. Полный номер карты, CVC и секретные ключи в диагностике не нужны.
- отклонен только один платеж или все списания с перевыпущенных карт;
- провайдер создал платеж и вернул canceled, failed или requires_action;
- запрос до провайдера не дошел из-за очереди, тайм-аута или ошибки API;
- платеж успешен у провайдера, но ваша система не продлила подписку;
- новый способ оплаты сохранен, но подписка продолжает использовать старый;
- ручная оплата проходит, а списание off-session отклоняется;
- повторные попытки не запускаются либо создают несколько платежей;
- доступ отключен сразу после первого временного отказа.
Эти варианты требуют разных исправлений. Если провайдер не получил запрос, замена карты ни при чем. Если платеж успешен, а доступ не продлен, проблема в синхронизации статусов. Если сохраненный способ оплаты больше не действителен, нужно предложить пользователю безопасно привязать новый.
Почему перевыпуск карты влияет на автоплатеж
Изменился платежный идентификатор
Сайт не должен хранить номер карты и CVC. Для автоплатежей платежный провайдер возвращает безопасный идентификатор сохраненного способа оплаты. После перевыпуска старый идентификатор может продолжить работать, автоматически связаться с обновленными реквизитами или стать непригодным. Поведение определяет провайдер и участники карточной сети, а не код сайта.
Карта была потеряна или украдена
При перевыпуске из-за окончания срока или повреждения некоторые системы обновляют данные card-on-file. При заявлении об утрате, краже или компрометации автоматическая передача новых реквизитов может быть заблокирована из соображений безопасности. В таком случае пользователь должен самостоятельно привязать новую карту через платежную форму провайдера.
Банк требует дополнительное подтверждение
Первое списание с обновленного способа оплаты может потребовать действия держателя карты. Off-session платеж не может молча завершить интерактивную аутентификацию. Провайдер вернет специальный статус или причину отказа, после чего сервис должен отправить пользователю безопасную ссылку на подтверждение или обновление способа оплаты.
Подписка использует не тот payment method
Новая карта может быть успешно сохранена в профиле клиента, но конкретная подписка, счет или договор остаются привязаны к старому идентификатору. Особенно часто это происходит, когда у клиента несколько подписок, способов оплаты или уровней настроек: default у customer, default у subscription и payment method конкретного invoice.
Отказ временный, а система считает его окончательным
Эмитент или эквайер может быть временно недоступен, на счете может не хватать средств, а антифрод может отклонить конкретную попытку. Такие ситуации не означают, что привязку нужно немедленно удалять. Нужна классификация причины, ограниченный график повторов и уведомление пользователя. Бесконечно повторять списание тоже нельзя.
Пошаговая диагностика одного неуспешного автоплатежа
- Найдите подписку в своей базе и зафиксируйте ее текущий статус, paid_until, тариф и сохраненный payment_method_id.
- Откройте клиента и платеж у провайдера по внутренним идентификаторам, не по последним цифрам карты.
- Проверьте, был ли запрос создан, принят и обработан, а также сохраните provider payment id.
- Прочитайте машинный код cancellation_details, decline_code или аналогичное поле, а не только текст для оператора.
- Сверьте способ оплаты платежа со способом, назначенным подписке и клиенту по умолчанию.
- Проверьте webhook: подпись, время доставки, HTTP-ответ, повторы и факт обработки события.
- Сравните состояние у провайдера с локальным состоянием подписки и счета.
- Убедитесь, что повторная попытка использует новый idempotency key для новой операции, но не создает дубль той же попытки.
- Проверьте, получил ли пользователь уведомление и рабочую ссылку на замену способа оплаты.
- После исправления повторите сценарий на тестовой подписке и только затем обработайте реальные записи.
Если интерфейс провайдера показывает обновленные последние цифры и срок действия, это еще не доказывает, что ваша подписка использует актуальный объект. Сравнивайте идентификаторы payment method и иерархию настроек. Не переносите реквизиты между объектами вручную.
Как читать причину отказа
Провайдеры используют разные названия, но причины удобно разделить на четыре группы. От этого зависит, повторять платеж, просить действие пользователя или остановить списания.
- временные: недостаточно средств, временная недоступность банка, сетевой сбой или ограничение провайдера;
- постоянные для старой привязки: карта закрыта, сохраненный способ недоступен, разрешение отозвано;
- требующие участия пользователя: дополнительная аутентификация, подтверждение нового способа, обновление реквизитов;
- ошибки интеграции: неверный customer, payment method другого магазина, неправильная валюта, идемпотентность или состояние счета.
Не делайте бизнес-решение по локализованной строке вроде «операция отклонена». Используйте стабильный код провайдера и храните его вместе с payment attempt. Отображаемый пользователю текст должен быть понятным, но не раскрывать внутренние детали антифрода.
Безопасное обновление карты пользователем
Новые реквизиты должен собирать платежный виджет, hosted page или SDK провайдера. Ваш сервер получает только идентификатор сохраненного способа и ограниченные метаданные, разрешенные провайдером. Нельзя просить пользователя отправить номер карты в чат, письмо или форму поддержки. CVC нельзя сохранять для будущих списаний.
- Создайте на сервере короткоживущую сессию привязки для авторизованного пользователя.
- Откройте платежную форму провайдера по HTTPS с корректным назначением сохранения карты.
- Получите подтвержденный payment_method_id или аналогичный идентификатор только от провайдера.
- Проверьте принадлежность объекта вашему магазину и нужному customer.
- В транзакции назначьте новый способ нужной подписке или клиенту согласно модели продукта.
- Не удаляйте старый способ до подтверждения сохранения нового и завершения перехода.
- Запустите одну контролируемую оплату или повтор счета по правилам провайдера.
- После успеха обновите подписку, доступ и историю попыток, затем уведомите пользователя.
Если провайдер поддерживает отдельную привязку на нулевую сумму, используйте ее по официальному сценарию. Если сохранение происходит во время обычной оплаты, явно отличайте первый пользовательский платеж от будущих безакцептных списаний и фиксируйте согласие в соответствии с договором и требованиями провайдера.
Почему новая карта сохраняется, но подписка не обновляется
В модели данных должен существовать один понятный источник выбора способа оплаты. Если одновременно есть default_payment_method у клиента, отдельное поле в subscriptions и копия в локальной таблице, легко обновить только один уровень. Следующий invoice выберет старое значение, хотя в личном кабинете уже показывается новая карта.
- зафиксируйте приоритет: способ счета, подписки, клиента или системный fallback;
- храните идентификатор провайдера, а не копию карточных реквизитов;
- обновляйте локальную запись только после подтверждения провайдера;
- проверяйте tenant, магазин и customer перед привязкой;
- добавьте аудит: кто, когда и для какой подписки сменил способ оплаты;
- не используйте последние четыре цифры как уникальный ключ;
- обрабатывайте несколько подписок пользователя явно, не массово по совпадению email.
Как устроить повторные попытки без дублей
Повторять платеж следует по ограниченной политике. Временный отказ можно попробовать снова позже, а недействительную карту бессмысленно списывать десятки раз. Провайдер может иметь собственные smart retries, поэтому локальный cron не должен дублировать встроенный график. Выберите один механизм и синхронизируйте его с состоянием счета.
- создавайте отдельную запись payment_attempt для каждой фактической попытки;
- используйте уникальный idempotency key на бизнес-операцию и повторяйте тот же запрос с тем же ключом после сетевой неопределенности;
- не создавайте новый платеж, пока не проверен статус предыдущего у провайдера;
- ограничьте число повторов и интервал между ними;
- останавливайте автоматические повторы при permanent decline или запросе новой карты;
- после обновления payment method явно перезапускайте неоплаченный invoice, если это допускает API;
- обрабатывайте webhook идемпотентно по event id и provider object id.
Если запрос завершился тайм-аутом, нельзя считать его неуспешным и сразу создавать новый. Сначала запросите состояние операции по provider id или idempotency key. Иначе одно списание может пройти, а второе будет создано повторно.
Когда отключать доступ после неуспешного списания
Отключение доступа должно следовать бизнес-политике, а не первому техническому отказу. Для подписки обычно вводят состояния active, past_due или grace_period, unpaid и canceled. Временная ошибка переводит подписку в промежуточное состояние, запускает уведомления и ограниченные повторы. Окончательное отключение происходит после завершения grace period, постоянного отказа или явной отмены.
- paid_until не изменяется от одного неуспешного запроса;
- успешный webhook продлевает доступ идемпотентно один раз;
- поздний успешный платеж умеет восстановить доступ по утвержденным правилам;
- отмена подписки и ошибка оплаты являются разными состояниями;
- повторный webhook не добавляет второй период доступа;
- ручная оплата корректно закрывает открытый долг или invoice;
- оператор видит причину, график повторов и последнее уведомление.
Точные сроки и юридические условия зависят от продукта и договора. Важно, чтобы одно и то же правило применялось в billing, личном кабинете и системе выдачи прав, а не было продублировано тремя разными cron-скриптами.
Webhook и сверка состояния
Автоплатежи обрабатываются асинхронно. HTTP-ответ на создание операции не всегда является финальным результатом. Подтверждайте подпись webhook, сохраняйте event id, отвечайте быстро и переносите тяжелую обработку в очередь. Повторная доставка того же события не должна повторно продлевать подписку.
Одних webhook недостаточно: доставка может задержаться, endpoint может быть временно недоступен, а событие — обработаться с ошибкой. Добавьте периодическую reconciliation-задачу, которая берет платежи в промежуточных состояниях, запрашивает актуальный статус у провайдера и исправляет расхождения. Источником финансового статуса остается объект провайдера, а локальная база хранит его отражение и бизнес-состояние доступа.
Что сообщать пользователю
Письмо или уведомление должно объяснять действие, а не внутренний код ошибки. Не пишите, что карта «заблокирована», если провайдер этого не подтвердил. Дайте пользователю безопасную ссылку в личный кабинет, срок льготного периода, дату следующей попытки и возможность отключить автоплатеж.
- платеж не прошел и подписка временно ожидает оплату;
- после перевыпуска может потребоваться повторно привязать карту;
- обновить способ можно только в защищенном личном кабинете;
- сервис не просит присылать номер карты или CVC;
- указана дата следующей попытки либо сообщено, что повторы остановлены;
- понятно, когда изменится доступ и как отменить подписку.
Как проверить исправление
- новый payment method сохраняется через форму провайдера и принадлежит нужному customer;
- конкретная подписка использует новый идентификатор, а не старый default;
- одна повторная попытка создает не более одного платежа;
- сетевой тайм-аут не приводит к двойному списанию;
- временный и постоянный отказ запускают разные сценарии;
- платеж, требующий действия пользователя, открывает корректный flow подтверждения;
- успешный webhook продлевает доступ ровно один раз;
- повторная и запоздалая доставка события не ломает статус подписки;
- reconciliation исправляет пропущенное событие;
- уведомление содержит рабочую ссылку и не раскрывает платежные данные.
В тестовом окружении проверьте успешную привязку, истекшую карту, недостаток средств, требование аутентификации, отозванное разрешение, задержку webhook и повтор одного события. Не ограничивайтесь тестом успешной оплаты.
Типичные ошибки
- ожидать, что данные любой перевыпущенной карты обновятся автоматически;
- просить клиента передать реквизиты карты оператору поддержки;
- сохранять CVC или полный номер карты в своей базе и логах;
- обновить карту у customer, но оставить старую у subscription;
- повторять все отказы по одному графику без классификации причин;
- создавать новый платеж после тайм-аута без проверки предыдущего;
- отключать доступ после первого временного decline;
- продлевать подписку по любому входящему webhook без проверки подписи и статуса;
- считать email или последние четыре цифры уникальным идентификатором клиента;
- не давать пользователю способ самостоятельно заменить карту и отменить автоплатеж.
Профилактика сбоев автоплатежа
Регулярно сверяйте подписки, платежи и доступы, храните историю попыток и наблюдайте долю отказов по стабильным кодам провайдера. Резкий рост после обновления интеграции должен останавливать rollout или включать ручную проверку. Обновление SDK, API-версии и webhook-схемы тестируйте на полном наборе статусов.
- личный кабинет позволяет заменить и удалить способ оплаты;
- перед окончанием срока действия отправляется нейтральное напоминание, если провайдер сообщает такой признак;
- правила retry и grace period документированы и одинаковы во всех сервисах;
- payment attempts и webhook events имеют уникальные ограничения в базе;
- промежуточные статусы автоматически сверяются с API провайдера;
- секретные ключи и платежные данные не попадают в логи;
- метрики показывают конверсию повторов, причины отказов и время восстановления подписки;
- служба поддержки видит безопасную диагностику без доступа к карточным реквизитам.
Когда нужна помощь с автоплатежами
Если после перевыпуска карты автоплатежи перестали работать, я могу проверить привязку payment method, настройки подписки, коды отказов, повторы, webhook, идемпотентность и связь оплаты с доступом. Для оценки пришлите название платежного провайдера, обезличенные идентификаторы тестового клиента и платежа, машинный код отказа, последовательность статусов и описание ожидаемой политики подписки без номеров карт, CVC и секретных ключей.