Development of installment plan functionality on 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1177
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Developing Installment Payment Functionality for 1C-Bitrix

An installment plan allows a customer to pay for goods in parts without interest (unlike a loan). The financial side is provided by a bank or the store itself (own installment plan). Technically, 1C-Bitrix needs to implement calculation, display of terms, checkout, and payment control.

Two Installment Variants

1. Bank Installment (via bank widget). A bank (Tinkoff, Halva, Sberbank BNPL) provides SDK/widget — the customer arranges an installment plan right on the site. The store receives the full amount immediately, the bank takes a commission. The technical task is integration with the bank's API and embedding the "Buy on Installment" button.

2. Store's Own Installment. The store itself splits the payment into parts and controls payments. More complex technically, but no bank commissions. Must store payment schedules and remind clients.

Bank Installment Integration

Let's consider Tinkoff Installment ("Dolya") as an example:

Step 1: Button on product card.

// Tinkoff widget
TinkoffCredit.request({
    shopId: '12345',
    showcaseId: '67890',
    items: [{
        name: productName,
        quantity: 1,
        price: productPrice,
    }],
    sum: productPrice,
    orderNumber: 'PRE-' + Date.now(),
});

Step 2: Order creation in Bitrix. Upon successful bank decision — create an order via \Bitrix\Sale\Order::create(), attach "Tinkoff Installment" payment system, save the loan_id from the bank in order properties.

Step 3: Webhook from bank. The bank notifies about the final decision (approved/rejected) and payment to the store. The webhook handler updates the order status.

For Halva (Sovcombank), Split VTB integration — similar scheme, but different API.

Own Installment: Architecture

Data storage. Table b_local_installment_plan:

Field Description
ID Primary key
ORDER_ID Link to Bitrix order
USER_ID Customer
TOTAL_AMOUNT Full amount
DOWN_PAYMENT First payment
INSTALLMENTS_COUNT Number of parts
INSTALLMENT_AMOUNT Amount per part
CURRENCY Currency
STATUS ACTIVE, COMPLETED, OVERDUE, CANCELLED

Table b_local_installment_payment — payment schedule:

Field Description
PLAN_ID Link to plan
PAYMENT_NUMBER Payment number (1, 2, 3...)
DUE_DATE Payment date
AMOUNT Amount
STATUS PENDING, PAID, OVERDUE
PAID_AT Actual payment date

Payment Schedule Calculation

function createInstallmentSchedule(int $planId, float $totalAmount, float $downPayment, int $installmentsCount): void
{
    $remainingAmount = $totalAmount - $downPayment;
    $installmentAmount = round($remainingAmount / $installmentsCount, 2);

    // Rounding correction for last payment
    $lastPaymentAmount = $remainingAmount - ($installmentAmount * ($installmentsCount - 1));

    for ($i = 1; $i <= $installmentsCount; $i++) {
        $dueDate = (new DateTime())->modify('+' . ($i * 30) . ' days');
        InstallmentPaymentTable::add([
            'PLAN_ID' => $planId,
            'PAYMENT_NUMBER' => $i,
            'DUE_DATE' => $dueDate,
            'AMOUNT' => ($i === $installmentsCount) ? $lastPaymentAmount : $installmentAmount,
            'STATUS' => 'PENDING',
        ]);
    }
}

Display on Product Card and Cart

On the product page — "Buy on Installment" block:

Cost: 30,000 rubles
Installment for 6 months:
├── First payment: 5,000 rubles (today)
└── 5 payments of 5,000 rubles each every 30 days

Dynamic calculation when selecting the number of months — via AJAX request to calculation endpoint:

// /local/ajax/installment_calc.php
$price = (float)$_POST['price'];
$months = (int)$_POST['months'];
$downPercent = 0.2; // 20% first payment
$down = round($price * $downPercent, 2);
$monthly = round(($price - $down) / ($months - 1), 2);
echo json_encode(['down' => $down, 'monthly' => $monthly]);

Payment Control and Overdue

An agent or cron checks for overdue payments daily:

$overdue = InstallmentPaymentTable::getList([
    'filter' => ['STATUS' => 'PENDING', '<DUE_DATE' => new DateTime()],
])->fetchAll();

foreach ($overdue as $payment) {
    InstallmentPaymentTable::update($payment['ID'], ['STATUS' => 'OVERDUE']);
    // Notify client
    sendOverdueNotification($payment);
    // If overdue > 30 days — escalate to manager
}

Customer Personal Account

The /personal/installments/ page shows:

  • Active installment plans with payment progress.
  • Schedule of upcoming payments.
  • History of paid parts.
  • Link to pay the next payment.

Development Timeline

Option Scope Timeline
Bank Widget Integration Tinkoff or Halva, button + webhook 3-5 days
Own Installment Storage, schedule, personal account, notifications 8-12 days
Full System Bank + own + overdue analytics 12-16 days