Setting Up Recurring Payments on 1C-Bitrix
A recurring payment is an automatic charge to the buyer's card without their repeated involvement. The card is linked once, and the store then initiates charges independently. Used for: automatic subscription renewals, regular deliveries, scheduled payments. Technically, this is not standard functionality of the 1C-Bitrix sale module — it requires additional implementation.
How It Works Technically
Recurring payments rely on card tokenization. On the first payment:
- The buyer enters their card; the payment system processes the transaction
- The system returns a card token (RebillId, RecurringId — each acquiring service uses its own term)
- The store saves the token, linking it to the buyer
- For subsequent charges, the store sends a request with the token — no need to re-enter the card
Saving a Card Token (YooKassa)
// On the first payment, request saving the card
$payment = $yookassaClient->createPayment([
'amount' => ['value' => $amount, 'currency' => 'RUB'],
'payment_method_data' => ['type' => 'bank_card'],
'confirmation' => ['type' => 'redirect', 'return_url' => $returnUrl],
'save_payment_method' => true, // key parameter
'capture' => true,
'description' => 'First payment, card binding',
], uniqid('', true));
// After successful payment in the callback:
$completedPayment = $yookassaClient->getPaymentInfo($paymentId);
$paymentMethodId = $completedPayment->getPaymentMethod()->getId();
// Save $paymentMethodId in the buyer's profile
UserCardTable::add([
'USER_ID' => $userId,
'PAYMENT_METHOD_ID'=> $paymentMethodId,
'LAST4' => $completedPayment->getPaymentMethod()->getLast4(),
'CARD_TYPE' => $completedPayment->getPaymentMethod()->getCardType(),
'ACTIVE' => 'Y',
]);
Subsequent Charge via Token
public function chargeRecurrent(int $userId, float $amount, string $description): bool
{
$card = UserCardTable::getActiveCard($userId);
if (!$card) {
return false;
}
try {
$payment = $yookassaClient->createPayment([
'amount' => ['value' => number_format($amount, 2, '.', ''), 'currency' => 'RUB'],
'payment_method_id' => $card['PAYMENT_METHOD_ID'], // saved card token
'capture' => true,
'description' => $description,
], uniqid('', true));
// Recurring payments immediately go to succeeded or pending status
if ($payment->getStatus() === 'succeeded') {
return true;
}
// Handle via webhook
return false;
} catch (\Exception $e) {
// Log and notify the user
return false;
}
}
1C-Bitrix Task Scheduler
For regular charges, use 1C-Bitrix agents:
// Register an agent when a subscription is created
\CAgent::AddAgent(
'\MyModule\RecurringAgent::run(' . $subscriptionId . ');',
'my_module',
'N',
86400, // interval in seconds (1 day)
date('d.m.Y H:i:s', strtotime('+1 month')), // first run date
'Y',
date('d.m.Y H:i:s', strtotime('+1 month'))
);
// Agent class
class RecurringAgent
{
public static function run(int $subscriptionId): string
{
$subscription = SubscriptionTable::getById($subscriptionId)->fetch();
if (!$subscription || $subscription['STATUS'] !== 'ACTIVE') {
return ''; // empty string = delete the agent
}
$charged = (new RecurringPaymentService())->chargeRecurrent(
$subscription['USER_ID'],
$subscription['AMOUNT'],
'Subscription renewal #' . $subscriptionId
);
if (!$charged) {
// Mark subscription as problematic and notify
}
// Return the method name for the next run
return '\MyModule\RecurringAgent::run(' . $subscriptionId . ');';
}
}
Charge Error Handling
The card may be blocked, the limit exceeded, or funds may be insufficient. Standard retry strategy:
- Day 0: first attempt — failure
- Day 1: retry
- Day 3: retry + email to buyer
- Day 7: final attempt + cancellation notification
Timeline
| Task | Duration |
|---|---|
| Saving card token on first payment | 1 day |
| Recurring charge mechanism + agents | 1–2 days |
| Error handling and notifications | 1 day |







