1C-Bitrix Integration with Magnit Instalment Service (Belarus)
"Magnit" is an instalment programme from VTB Bank (Belarus). It is one of the most common consumer credit instruments in the Belarusian market. The buyer arranges instalment payments for 6–36 months and the store receives the amount from VTB. Integration with a 1C-Bitrix website is a standard payment system handler with a redirect to the bank's page.
VTB Belarus Partner API
VTB provides a REST API for online stores. Authentication — Basic Auth (partner login/password) or OAuth 2.0, depending on the connection plan. When requesting a connection, clarify: the authentication type, test environment, and notification format.
Basic scheme:
- The store sends
POST /api/v1/credits/applicationswith order and customer data - VTB returns
application_idandredirect_url - The customer fills in the application in the VTB interface
- VTB sends a webhook with the decision
- On approval — the funds are transferred to the store
Payment System Handler
class MagnitVtbHandler extends \Bitrix\Sale\PaySystem\ServiceHandler
{
public function initiatePay(
\Bitrix\Sale\Payment $payment,
\Bitrix\Main\Request $request = null
) {
$order = $payment->getOrder();
// Available instalment terms (months)
$availableTerms = array_map('intval', explode(',',
$this->getBusinessValue($payment, 'AVAILABLE_TERMS') ?? '6,12,24,36'
));
$payload = [
'partnerOrderId' => 'BX-' . $order->getId(),
'totalAmount' => $payment->getSum(),
'currency' => 'BYN',
'terms' => $availableTerms,
'goods' => $this->buildGoodsList($order),
'client' => [
'firstName' => $order->getPropertyValueByCode('NAME'),
'lastName' => $order->getPropertyValueByCode('LAST_NAME'),
'middleName' => $order->getPropertyValueByCode('SECOND_NAME'),
'mobilePhone' => $this->normalizePhone($order->getPropertyValueByCode('PHONE')),
'email' => $order->getPropertyValueByCode('EMAIL'),
],
'urls' => [
'success' => $this->getSuccessUrl($payment),
'fail' => $this->getFailUrl($payment),
'callback' => $this->getNotificationUrl($payment),
],
];
$response = $this->sendRequest('POST', '/api/v1/credits/applications', $payload);
if (empty($response['redirectUrl'])) {
$this->setError('VTB Magnit: redirectUrl not received');
return \Bitrix\Sale\PaySystem\ServiceResult::create();
}
$this->saveApplicationId($payment->getField('ID'), $response['applicationId']);
$result = new \Bitrix\Sale\PaySystem\ServiceResult();
$result->setPaymentUrl($response['redirectUrl']);
return $result;
}
private function buildGoodsList(\Bitrix\Sale\Order $order): array
{
$goods = [];
foreach ($order->getBasket() as $item) {
$goods[] = [
'name' => mb_substr($item->getField('NAME'), 0, 200),
'price' => round($item->getPrice(), 2),
'quantity' => (int)$item->getQuantity(),
'article' => (string)$item->getProductId(),
'brand' => $item->getField('DETAIL_PAGE_URL'), // or from product property
];
}
return $goods;
}
private function normalizePhone(string $phone): string
{
$digits = preg_replace('/\D/', '', $phone);
// Belarusian format: +375XXXXXXXXX
if (strlen($digits) === 11 && $digits[0] === '8') {
$digits = '375' . substr($digits, 1);
}
return '+' . ltrim($digits, '+');
}
}
Webhook from VTB
VTB sends a POST to callback_url when the application status changes. Verification via HMAC signature or IP whitelist (VTB IP ranges):
public function processRequest(\Bitrix\Sale\Payment $payment, \Bitrix\Main\Request $request)
{
$allowedIps = ['194.XXX.XXX.0/24']; // VTB Belarus IP range
if (!$this->isAllowedIp($request->getServer()->get('REMOTE_ADDR'), $allowedIps)) {
http_response_code(403);
exit;
}
$data = json_decode(file_get_contents('php://input'), true);
$result = new \Bitrix\Sale\PaySystem\ServiceResult();
switch ($data['status'] ?? '') {
case 'APPROVED':
case 'ISSUED': // Credit issued, funds received by the store
$result->setOperationType(\Bitrix\Sale\PaySystem\ServiceResult::MONEY_COMING);
$payment->setPaid('Y');
break;
case 'DECLINED':
// Application declined — notify the customer
\Bitrix\Main\Mail\Event::send([
'EVENT_NAME' => 'INSTALLMENT_DECLINED',
'LID' => SITE_ID,
'C_FIELDS' => ['ORDER_ID' => $payment->getOrderId()],
]);
break;
}
http_response_code(200);
echo json_encode(['status' => 'ok']);
return $result;
}
"Calculate Instalment" Widget on the Site
On the product page and in the cart we show a monthly payment calculator:
function calcMagnitInstallment(price) {
const terms = [6, 12, 24, 36];
const container = document.getElementById('magnit-installment');
container.innerHTML = terms.map(t =>
`<div class="term-option">
<span>${t} mo.</span>
<strong>${Math.ceil(price / t)} /mo.</strong>
</div>`
).join('');
}
Timeline
| Phase | Duration |
|---|---|
| API connection setup and test environment | 1 day |
| Payment system handler | 2–3 days |
| Webhook and status handling | 1–2 days |
| Refunds via API | 1 day |
| Instalment calculator widget | 0.5 days |
| Testing | 2 days |
| Total | 8–10 days |







