Setting Up Instalment Terms Display on a 1C-Bitrix Product Card
Displaying instalment options on a product page means calculating the monthly payment and showing a partner's terms (a bank or BNPL service) directly on the card. This is implemented by storing instalment parameters and calculating them on the frontend or server.
Where Instalment Terms Come From
Two main scenarios:
Scenario 1 — Fixed partners. The shop has an agreement with one or two banks; the terms are known in advance (interest rate, periods, minimum amount). Data is stored in site settings or a dedicated iblock.
Scenario 2 — Dynamic terms via API. The bank/BNPL partner provides an API from which current terms for a specific amount are fetched. Examples: Tinkoff Instalment, Halva, Split.
Storing Partner Terms in Bitrix
For fixed terms, create an HL-iblock InstallmentPlans:
| Field | Type | Description |
|---|---|---|
UF_PARTNER |
String | Partner name |
UF_LOGO |
File | Logo |
UF_MIN_AMOUNT |
Decimal | Minimum product amount |
UF_MONTHS |
String | Available periods (6,10,12,24) |
UF_RATE |
Decimal | Rate (0 for interest-free) |
UF_ACTIVE |
Flag | Whether the plan is active |
Calculating the Monthly Payment
For interest-free instalment (rate = 0):
monthly = price / months
For instalment with an interest rate (annuity payment):
monthly = price * (rate/12) / (1 - (1 + rate/12)^(-months))
PHP calculation implementation:
function calcInstallment(float $price, int $months, float $annualRate): float {
if ($annualRate <= 0) {
return $price / $months;
}
$r = $annualRate / 12 / 100;
return $price * $r / (1 - pow(1 + $r, -$months));
}
JavaScript for dynamic recalculation when the period changes:
function calcInstallment(price, months, annualRate) {
if (annualRate <= 0) return price / months;
const r = annualRate / 12 / 100;
return price * r / (1 - Math.pow(1 + r, -months));
}
document.querySelectorAll('.installment-months').forEach(btn => {
btn.addEventListener('click', () => {
const months = parseInt(btn.dataset.months);
const rate = parseFloat(btn.dataset.rate);
const price = parseFloat(document.querySelector('[data-price]').dataset.price);
const monthly = calcInstallment(price, months, rate);
document.querySelector('.monthly-payment').textContent =
monthly.toFixed(2) + ' /mo.';
});
});
Displaying the Block on the Product Card
In the catalog.element template, add the block after the price:
// Load instalment plans matching the amount
$price = (float)$arResult['CATALOG_PRICE_1'];
$plans = \Local\Installment\InstallmentPlanTable::getList([
'filter' => [
'=UF_ACTIVE' => true,
'<=UF_MIN_AMOUNT' => $price,
],
'order' => ['UF_MIN_AMOUNT' => 'ASC'],
])->fetchAll();
The HTML block with terms — a list of partners with their logos and period selection buttons. Each partner shows the minimum monthly payment (based on the maximum period).
Integration with the Bank API
If the partner provides a calculation API (e.g. Tinkoff):
// Cache the API response for 10 minutes to avoid a request on every card open
$cacheKey = 'installment_' . (int)$price;
$cache = \Bitrix\Main\Data\Cache::createInstance();
if ($cache->initCache(600, $cacheKey, '/installment/')) {
$data = $cache->getVars();
} else {
$data = \Local\Installment\TinkoffApiClient::getPlans($price);
$cache->startDataCache();
$cache->endDataCache($data);
}
Points to Keep in Mind
- For products below the partner's minimum threshold, do not show the instalment block at all
- Legal texts ("instalment provided by a partner bank") should be displayed alongside the block
- When the price changes via JS (configuration selection), recalculate instalment as well
| Stage | Time |
|---|---|
| Partner terms storage | 1–2 h |
| Payment calculation (PHP + JS) | 2–3 h |
| Block on the product card | 3–4 h |
| Bank API integration (optional) | 4–8 h |







