1C-Bitrix integration with the Cherepakh installment plan (Belarus)

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
    1175
  • 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

1C-Bitrix Integration with Cherepakha Instalment Service (Belarus)

"Cherepakha" is an instalment service from MTBank (Belarus). It is positioned as fast instalment without a bank visit: the buyer goes through the verification online in a few minutes. For the store — receiving the full amount minus the commission. MTBank provides a REST API for integration with eCommerce platforms.

MTBank API Interaction Scheme

MTBank uses OAuth 2.0 Client Credentials for partner authorisation:

class MtbankOAuthClient
{
    private ?string $accessToken = null;
    private ?int $expiresAt = null;

    public function getToken(): string
    {
        if ($this->accessToken && $this->expiresAt > time() + 60) {
            return $this->accessToken;
        }

        $response = $this->httpPost('/oauth/token', [
            'grant_type'    => 'client_credentials',
            'client_id'     => MTBANK_CLIENT_ID,
            'client_secret' => MTBANK_CLIENT_SECRET,
            'scope'         => 'installment',
        ]);

        $this->accessToken = $response['access_token'];
        $this->expiresAt   = time() + $response['expires_in'];

        // Cache in Bitrix Cache
        \Bitrix\Main\Data\Cache::createInstance()->set(
            'mtbank_token',
            ['token' => $this->accessToken, 'expires' => $this->expiresAt],
            $response['expires_in'] - 120
        );

        return $this->accessToken;
    }
}

Creating an Instalment Order

public function initiatePay(\Bitrix\Sale\Payment $payment, \Bitrix\Main\Request $request = null)
{
    $order   = $payment->getOrder();
    $termMap = ['3' => 3, '6' => 6, '12' => 12, '18' => 18, '24' => 24];
    $term    = $termMap[$this->getBusinessValue($payment, 'TERM')] ?? 12;

    $payload = [
        'externalOrderId' => 'BITRIX-' . $order->getId(),
        'amount'          => (float)$payment->getSum(),
        'currency'        => 'BYN',
        'term'            => $term,
        'description'     => 'Order ' . $order->getField('ACCOUNT_NUMBER'),
        'successUrl'      => $this->getSuccessUrl($payment),
        'failUrl'         => $this->getFailUrl($payment),
        'notifyUrl'       => $this->getNotificationUrl($payment),
        'customer'        => [
            'firstName' => $order->getPropertyValueByCode('NAME'),
            'lastName'  => $order->getPropertyValueByCode('LAST_NAME'),
            'phone'     => preg_replace('/\D/', '', $order->getPropertyValueByCode('PHONE')),
            'email'     => $order->getPropertyValueByCode('EMAIL'),
        ],
        'items' => $this->formatBasketItems($order->getBasket()),
    ];

    $token    = $this->oauthClient->getToken();
    $response = $this->httpPost('/v1/installment/orders', $payload, [
        'Authorization' => "Bearer {$token}",
    ]);

    if (empty($response['paymentUrl'])) {
        throw new \RuntimeException('MTBank Cherepakha: empty paymentUrl');
    }

    // Save MTBank orderId for callbacks and refunds
    \Bitrix\Main\Application::getConnection()->queryExecute(
        "INSERT INTO bl_mtbank_orders (bitrix_order_id, mtbank_order_id, status, created_at)
         VALUES (?, ?, 'pending', NOW())",
        [$order->getId(), $response['orderId']]
    );

    $result = new \Bitrix\Sale\PaySystem\ServiceResult();
    $result->setPaymentUrl($response['paymentUrl']);
    return $result;
}

Basket Items Formatting

MTBank API requires the order items for amount verification:

private function formatBasketItems(\Bitrix\Sale\Basket $basket): array
{
    $items = [];
    foreach ($basket as $item) {
        $items[] = [
            'name'      => mb_substr($item->getField('NAME'), 0, 255),
            'quantity'  => (int)$item->getQuantity(),
            'unitPrice' => round($item->getPrice(), 2),
            'totalPrice'=> round($item->getFinalPrice(), 2),
            'sku'       => (string)$item->getProductId(),
        ];
    }
    // Add delivery if present
    $shipment = $basket->getOrder()->getShipmentCollection()->getIterator()->current();
    $deliveryPrice = $shipment ? $shipment->getPrice() : 0;
    if ($deliveryPrice > 0) {
        $items[] = [
            'name'       => 'Delivery',
            'quantity'   => 1,
            'unitPrice'  => $deliveryPrice,
            'totalPrice' => $deliveryPrice,
            'sku'        => 'DELIVERY',
        ];
    }
    return $items;
}

Callback Processing

MTBank signs notifications with HMAC-SHA256 using a secret key:

public function processRequest(\Bitrix\Sale\Payment $payment, \Bitrix\Main\Request $request)
{
    $body      = file_get_contents('php://input');
    $signature = $request->getServer()->get('HTTP_X_MTBANK_SIGNATURE');
    $expected  = hash_hmac('sha256', $body, MTBANK_WEBHOOK_SECRET);

    if (!hash_equals($expected, $signature ?? '')) {
        http_response_code(400);
        $result = new \Bitrix\Sale\PaySystem\ServiceResult();
        $result->addError(new \Bitrix\Main\Error('Bad signature'));
        return $result;
    }

    $data   = json_decode($body, true);
    $result = new \Bitrix\Sale\PaySystem\ServiceResult();

    if ($data['status'] === 'APPROVED') {
        $result->setOperationType(\Bitrix\Sale\PaySystem\ServiceResult::MONEY_COMING);
        \Bitrix\Main\Application::getConnection()->queryExecute(
            "UPDATE bl_mtbank_orders SET status = 'approved' WHERE mtbank_order_id = ?",
            [$data['orderId']]
        );
        $payment->setPaid('Y');
    }
    return $result;
}

Service Limitations

The minimum order amount and maximum instalment term are defined by the contract with MTBank. In the handler we implement an isAvailable() method that checks the basket total before displaying the "Cherepakha" button.

Timeline

Phase Duration
MTBank OAuth client + token cache 1 day
Payment system handler 2 days
Callback + signature verification 1 day
Refunds 1 day
Testing in MTBank environment 2 days
Total 7–8 days