Автоплатежи в Bitrix через YooKassa: подписка, сохранение карты, webhook и повторные списания
Автоплатежи в 1С-Битрикс — это не просто кнопка «оплатить» в личном кабинете. В реальном проекте это отдельная платежная логика: пользователь активирует подписку, сайт сохраняет способ оплаты, YooKassa присылает webhook, система продлевает доступ, а cron или агент Bitrix выполняет повторные списания по расписанию.
Такая задача часто возникает в сервисах по подписке, личных кабинетах, SaaS-проектах, клубных программах, закрытых разделах сайта и любых проектах, где услуга должна автоматически продлеваться без ручного участия менеджера.
В этой статье разберем, как была реализована система автоплатежей в Bitrix: Highload-блок для хранения подписок, собственный обработчик YooKassa, webhook вместо ненадежного success.php, автоматические списания по cron, повторные попытки при ошибках и управление подпиской со стороны пользователя.
Подобные задачи относятся к кастомной разработке на Bitrix и PHP: подключение платежных систем, доработка личного кабинета, настройка webhook, автоматизация списаний и работа с Highload-блоками. Такие работы можно выполнить в рамках услуги доработки Bitrix и PHP-задачи.
Задача проекта
Нужно было реализовать механизм подписки с автоматическим продлением. Пользователь должен был иметь возможность включить или отключить автоплатеж в личном кабинете, а система — запомнить платежный метод и в дальнейшем автоматически списывать оплату за следующий период.
Основные требования:
- дать пользователю возможность активировать автоплатеж;
- сохранить
payment_method_idпосле первой успешной оплаты; - хранить данные подписки в отдельной сущности;
- автоматически продлевать подписку по расписанию;
- обрабатывать неудачные списания;
- делать несколько повторных попыток оплаты;
- отключать автоплатеж после превышения лимита ошибок;
- отправлять пользователю уведомления о состоянии подписки.
Снаружи для пользователя это выглядит просто: включил автоплатеж — подписка продлевается сама. Но внутри сайта это полноценная платежная подсистема с хранением статусов, дат, попыток, идентификаторов платежей и связи с заказами Bitrix.
Общая архитектура решения
Решение было разделено на несколько независимых частей, чтобы не смешивать интерфейс, платежную логику и фоновые задачи.
- Highload-блок для хранения подписок и данных автоплатежей.
- Собственный обработчик платежной системы Bitrix для работы с YooKassa API.
- Webhook-обработчик для фиксации успешных платежей.
- Cron или агент Bitrix для запуска автоматических списаний.
- Пользовательский компонент для включения и отключения автоплатежа.
- Почтовые события для уведомлений о подписке, успешных и неудачных списаниях.
Такой подход удобен тем, что каждая часть отвечает за свою задачу: компонент управляет интерфейсом, webhook подтверждает оплату, Highload-блок хранит состояние, а cron выполняет регулярную проверку подписок.
Хранение данных автоплатежей в Highload-блоке
В качестве центрального хранилища был выбран Highload-блок. Это удобный вариант для Bitrix, когда нужно хранить отдельную бизнес-сущность: подписки, платежные методы, технические статусы, количество попыток списания и дату следующего продления.
Основные поля Highload-блока:
UF_PAYMENT_USERID — ID пользователя
UF_PAYMENT_ID — payment_method_id / сохраненный способ оплаты
UF_PAYMENT_DATE — дата последней успешной оплаты
UF_PAYMENT_AMOUNT — сумма списания
UF_SUBSCRIPTION_PERIOD — период подписки в месяцах
UF_PAYMENT_CHECKAUTO — включен ли автоплатеж
UF_ATTEMPT_COUNT — количество неудачных попыток списания
UF_PAYMENT_STATUS — статус последней попытки оплаты
UF_PAYMENT_DATETIME — дата и время последней операции
Такая структура позволяет не только понять, активна ли подписка сейчас, но и обслуживать всю дальнейшую логику: когда списывать деньги, сколько попыток уже было, нужно ли отключать автоплатеж, какой платежный метод использовать и какой статус показать пользователю.
Если на проекте уже есть старая логика заказов, нестандартный личный кабинет или собственная система доступов, перед внедрением автоплатежей важно проверить архитектуру. Иногда сначала требуется навести порядок в коде, исправить ошибки после старых доработок или оптимизировать работу фоновых задач. В таких случаях полезен технический аудит сайта и производительности.
Собственная платежная система Bitrix для YooKassa
Для интеграции был создан отдельный обработчик платежной системы Bitrix. Пользовательские обработчики можно размещать в директории:
/bitrix/php_interface/include/sale_payment/my_yookassa/
Внутри структуры были вынесены основные файлы:
/bitrix/php_interface/include/sale_payment/my_yookassa/
handler.php
description.php
payment.php
result.php
Через обработчик создается платеж в YooKassa, передается сумма, пользователь, технические метаданные и URL возврата. Для работы с API использовался официальный SDK YooKassa через Composer.
Важный момент: для автоплатежей недостаточно просто провести обычную оплату.
Нужно получить и сохранить payment_method_id. Именно этот идентификатор позволяет
в будущем выполнять повторные списания без повторного ввода карты пользователем.
Активация автоплатежа пользователем
Если пользователь ранее уже оплатил подписку, но платежный метод не был сохранен, простого
переключателя «Включить автоплатеж» недостаточно. Сначала нужно снова провести пользователя
через платеж YooKassa, получить разрешение на сохранение способа оплаты и сохранить
payment_method_id.
Логика активации была построена так:
- Пользователь нажимает «Включить автоплатеж» в личном кабинете.
- Сайт создает платеж в YooKassa.
- Пользователь переходит на страницу оплаты.
- После успешной оплаты система получает
payment_method_id. - Далее выполняется возврат средств, если оплата нужна только для привязки метода.
- В Highload-блок записывается сохраненный способ оплаты.
- Флаг автоплатежа переводится в активное состояние.
Такой сценарий позволяет не брать деньги просто за подключение автоплатежа, но при этом корректно получить платежный метод для будущих списаний.
Почему webhook надежнее, чем success.php
На первом этапе можно подумать, что успешную оплату достаточно обработать через страницу возврата,
например success.php. Но для платежной логики такой подход ненадежен.
Причины:
- пользователь может закрыть вкладку после оплаты;
- браузер может не вернуться на сайт;
- редирект не является гарантией успешного платежа;
- статус оплаты должен фиксироваться сервером, а не действием пользователя;
- страница возврата может открыться повторно или вручную.
Поэтому основная обработка была реализована через webhook YooKassa. Платежная система сама отправляет уведомление на сервер после изменения статуса платежа. На основании этого события сайт проверяет платеж и обновляет подписку.
/local/yookassa/webhook.php
Такой подход особенно важен для автоплатежей: если webhook не обработан корректно, пользователь может оплатить, но подписка не продлится, заказ не станет оплаченным или письмо не уйдет. Поэтому webhook — это центральная точка всей платежной интеграции.
Сохранение данных после успешной оплаты
После успешной оплаты нужно создать или обновить запись в Highload-блоке. Если у пользователя еще нет записи по подписке, она создается. Если запись уже есть — обновляются сумма, дата оплаты, срок подписки, статус автоплатежа и сохраненный способ оплаты.
$rsData = $entityDataClass::getList([
'filter' => [
'UF_PAYMENT_USERID' => $userId
],
]);
if (!$arItem = $rsData->fetch()) {
$entityDataClass->add([
'UF_PAYMENT_ID' => $paymentMethodId,
'UF_PAYMENT_DATE' => $paymentDate,
'UF_PAYMENT_USERID' => $userId,
'UF_PAYMENT_CHECKAUTO' => $isAutoPayment,
'UF_PAYMENT_AMOUNT' => $paymentAmount,
'UF_SUBSCRIPTION_PERIOD' => $subsPeriod
]);
} else {
$entityDataClass->update($arItem['ID'], [
'UF_PAYMENT_ID' => $paymentMethodId,
'UF_PAYMENT_DATE' => $paymentDate,
'UF_PAYMENT_CHECKAUTO' => $isAutoPayment,
'UF_PAYMENT_AMOUNT' => $paymentAmount,
'UF_SUBSCRIPTION_PERIOD' => $subsPeriod
]);
}
Так Highload-блок становится единым источником данных по подписке. Именно от него дальше зависит расчет даты следующего списания, отображение статуса в личном кабинете и запуск повторной оплаты.
Расчет даты окончания подписки
Один из важных моментов — корректно определить, когда нужно делать следующее списание. Нельзя просто каждый месяц списывать деньги у всех пользователей, потому что подписка может быть оплачена на 1, 2, 3, 6 или 12 месяцев.
Поэтому дата окончания оплаченного периода рассчитывается так:
дата последней оплаты + UF_SUBSCRIPTION_PERIOD месяцев
Пример:
$lastPaymentDate = new DateTime($arItem['UF_PAYMENT_DATE']);
$subscriptionPeriod = (int)$arItem['UF_SUBSCRIPTION_PERIOD'];
$expiryDate = (clone $lastPaymentDate)->modify("+{$subscriptionPeriod} months");
Если пользователь оплатил подписку на 6 месяцев, система не будет пытаться списывать деньги каждый месяц. Следующее автосписание произойдет только после окончания оплаченного периода.
Автоматические списания по cron или агенту Bitrix
Для запуска автоплатежей используется отдельная функция, которая выполняется по расписанию. Она выбирает активные подписки, рассчитывает дату окончания периода и проверяет, нужно ли выполнять очередное списание.
Основной сценарий:
- Получить все записи, где
UF_PAYMENT_CHECKAUTO = true. - Для каждой подписки взять дату последней оплаты.
- Прибавить
UF_SUBSCRIPTION_PERIODмесяцев. - Сравнить дату окончания периода с текущей датой.
- Если период закончился — инициировать списание через YooKassa.
- При успехе обновить дату последней оплаты и обнулить счетчик ошибок.
- При ошибке увеличить количество неудачных попыток.
Файл фоновой задачи можно вынести отдельно:
/local/php_interface/cron/auto_payment_cron.php
Пример запуска через cron:
0 0 * * * /usr/bin/php /home/bitrix/www/bitrix/modules/main/tools/cron_events.php
Проверку подписок удобно запускать один раз в день, например ночью. Для большинства подписочных сценариев этого достаточно, потому что списание не требует моментального запуска каждую минуту.
Если cron, агенты или фоновые задачи в Битрикс работают нестабильно, подписки могут не продлеваться вовремя. Это уже задача не только платежной интеграции, но и технического сопровождения сайта: проверка cron, прав доступа, логов, ошибок PHP и нагрузки на сервер.
Повторные попытки списания
Неудачное списание не всегда означает, что подписку нужно сразу отключать.
Например, на карте может временно не быть средств, банк может отклонить операцию,
платежная система может вернуть статус canceled или пользователь может решить проблему
в течение нескольких дней.
Поэтому была реализована логика повторных попыток. При неудачной оплате увеличивается счетчик:
UF_ATTEMPT_COUNT = UF_ATTEMPT_COUNT + 1
Алгоритм:
- первая неудачная попытка — повторить списание на следующий день;
- вторая неудачная попытка — выполнить еще один повтор;
- третья неудачная попытка — сделать финальную попытку;
- после превышения лимита — автоматически отключить автоплатеж.
if ($attemptCount >= 3) {
$entityDataClass->update($recordId, [
'UF_PAYMENT_CHECKAUTO' => false
]);
}
Это защищает систему от бесконечных попыток списания и одновременно дает пользователю время пополнить карту или выбрать другой способ оплаты.
Компонент управления автоплатежом в личном кабинете
Для пользователя был разработан отдельный компонент Bitrix, который показывает текущий статус автоплатежа и позволяет включить или отключить подписку без обращения к администратору.
Пример структуры компонента:
/local/components/mycompany/auto_payment/
.description.php
.parameters.php
component.php
ajax.php
class.php
templates/.default/template.php
Логика компонента:
- если автоплатеж активен — пользователь может его отключить;
- если автоплатеж выключен, но
payment_method_idуже сохранен — достаточно включить флаг; - если платежного метода нет — пользователь отправляется на YooKassa для привязки карты;
- после изменения статуса интерфейс обновляется через AJAX.
Такая доработка относится к разработке личного кабинета на Bitrix: здесь важно не только сохранить значение в базе, но и правильно связать интерфейс, текущую подписку, платежную систему и пользовательские уведомления.
Обновление статуса автоплатежа через AJAX
Для переключения автоплатежа использовался AJAX-обработчик. Он определяет текущего пользователя,
находит его запись в Highload-блоке и обновляет поле UF_PAYMENT_CHECKAUTO.
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['autopayment'])) {
$userId = $USER->GetID();
$autopaymentStatus = ($_POST['autopayment'] === 'Y') ? true : false;
$rsData = $entityDataClass->getList([
'filter' => [
'UF_PAYMENT_USERID' => $userId
],
]);
if ($arItem = $rsData->fetch()) {
$result = $entityDataClass->update($arItem['ID'], [
'UF_PAYMENT_CHECKAUTO' => $autopaymentStatus
]);
}
}
Важно, чтобы интерфейс показывал не значение по умолчанию, а фактическое состояние подписки. Иначе пользователь может видеть включенный автоплатеж, хотя в базе он отключен, или наоборот.
Обновление заказа Bitrix после оплаты
После подтверждения успешной оплаты через webhook нужно обновить не только Highload-блок, но и сам заказ Bitrix. Это нужно для корректной работы модуля sale, статусов заказа, личного кабинета, админки и стандартной истории оплат.
$paymentCollection = $order->getPaymentCollection();
foreach ($paymentCollection as $payment) {
if (!$payment->isPaid()) {
$payment->setPaid("Y");
}
}
$order->setField("STATUS_ID", "P");
$order->save();
В результате данные синхронизируются на двух уровнях: платеж в заказе отмечается как оплаченный, а Highload-блок хранит состояние подписки и данные для следующих автосписаний.
Почтовые уведомления
Для пользователя были подготовлены почтовые события и шаблоны. Такой подход удобен тем, что текст писем можно менять в админке Bitrix, не вмешиваясь в код автоплатежей.
Были предусмотрены уведомления:
- об успешном оформлении подписки;
- об успешном автоматическом списании;
- о неудачной попытке оплаты;
- об отключении автоплатежа после нескольких ошибок;
- о необходимости обновить платежный метод.
В письма можно передавать имя пользователя, email, сумму, дату операции, период подписки, статус платежа и ссылку на личный кабинет.
Типовые ошибки при реализации автоплатежей
Обработка оплаты через success.php вместо webhook
Если завязать продление подписки только на страницу возврата, часть оплат может не обработаться. Пользователь оплатит, но закроет вкладку, и сайт не узнает об успешном платеже.
Не сохраняется payment_method_id
Без сохраненного платежного метода невозможно выполнять автоматические списания. Обычный платеж и платеж с сохранением метода оплаты — это разные сценарии.
Неправильно считается дата следующего списания
Если не учитывать UF_SUBSCRIPTION_PERIOD, система может списывать деньги слишком рано
или слишком поздно. Особенно это критично для подписок на несколько месяцев.
Нет ограничения повторных попыток
Если не ограничить количество повторов, система может бесконечно пытаться списывать деньги с карты пользователя. Это плохо и технически, и с точки зрения пользовательского опыта.
Highload-блок и заказ Bitrix обновляются несинхронно
Если заказ отмечен как оплаченный, а подписка не обновилась, пользователь может потерять доступ. Если подписка продлена, а заказ не оплачен в админке, менеджер увидит некорректную картину.
Исправление подобных ошибок — это типичный пример технической доработки Bitrix-проекта: нужно смотреть код обработчика оплаты, webhook, Highload-блоки, cron, статусы заказа и пользовательский интерфейс.
Что проверить после внедрения
После реализации автоплатежей нужно протестировать не только первую оплату, но и весь жизненный цикл подписки.
- Пользователь может включить автоплатеж в личном кабинете.
- YooKassa корректно создает платеж.
- После оплаты сохраняется
payment_method_id. - Webhook приходит на сайт и обрабатывается сервером.
- Highload-блок обновляется после успешной оплаты.
- Заказ Bitrix получает статус оплаченного.
- Дата следующего списания рассчитывается с учетом периода подписки.
- Cron или агент запускает проверку подписок.
- Повторное списание выполняется через сохраненный платежный метод.
- Неудачные попытки увеличивают счетчик ошибок.
- После лимита ошибок автоплатеж отключается.
- Пользователь получает уведомления о статусе подписки.
Где может пригодиться такая система
Автоплатежи через YooKassa подходят для разных типов проектов:
- сайты с платной подпиской;
- SaaS-сервисы;
- онлайн-школы и закрытые курсы;
- клубные программы;
- личные кабинеты с регулярным доступом;
- платные разделы сайта;
- B2B-порталы с ежемесячной оплатой;
- сервисы, где нужно автоматическое продление услуг.
Посмотреть похожие задачи по платежным интеграциям, личным кабинетам, Bitrix, PHP, автоматизации и нестандартной бизнес-логике можно в разделе примеры работ.
Почему автоплатежи нельзя делать “на костылях”
В автоплатежах любая мелкая ошибка может привести к серьезной проблеме: деньги списались, а подписка не продлилась; webhook пришел, но не обработался; пользователь отключил автоплатеж, а cron все равно сделал списание; заказ в админке не оплачен, хотя услуга уже активирована.
Поэтому при разработке важно заранее продумать:
- структуру хранения подписок;
- связь подписки с пользователем и заказом;
- логику сохранения платежного метода;
- обработку webhook;
- проверку повторных уведомлений;
- расчет даты следующего списания;
- ограничение количества попыток;
- синхронизацию Highload-блока и заказа Bitrix;
- уведомления пользователю;
- ручную проверку спорных ситуаций администратором.
В AG Studio такие задачи решаются не как разовая вставка платежной кнопки, а как полноценная интеграция в существующую бизнес-логику проекта. Подробнее о подходе к разработке, поддержке и техническим задачам можно прочитать на странице о студии.
Результат
В результате была реализована полноценная система подписок и автоплатежей внутри Bitrix. Пользователь может включить автоплатеж в личном кабинете, система сохраняет платежный метод, webhook подтверждает оплату, Highload-блок хранит состояние подписки, а cron автоматически запускает следующие списания.
Дополнительно была реализована обработка неудачных попыток: система не отключает подписку сразу, а делает несколько повторов и только после превышения лимита выключает автоплатеж. Это делает решение более устойчивым и удобным для пользователя.
Если нужно подключить YooKassa, реализовать автоплатежи, настроить webhook, доработать личный кабинет, исправить ошибки в оплате или связать платежную систему с подписками в Bitrix, можно отправить задачу через страницу контактов.