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 |







