Integration with CloudKassir for 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
    1173
  • 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
    745
  • 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

CloudKassir Integration for 1C-Bitrix

CloudKassir is a cloud fiscal receipt service operating under Federal Law No. 54-FZ. It works on the same model as OrangeData and ATOL Online: the hardware is on the service's side, you pay per receipt processed, and you do not worry about maintaining physical cash registers. The CloudKassir API is simpler than its competitors — authentication is via login/password with Basic Auth, and there is no client certificate requirement. This lowers the entry threshold but does not eliminate the main challenges: VAT rate mapping, asynchrony, and correct line item formatting under 54-FZ.

CloudKassir API: Structure

Base URL: https://api.cloudkassir.ru/v1/. Authentication: Basic Auth, login and password from the personal account.

Key methods:

  • POST /receipts — submit a receipt
  • GET /receipts/{id} — receipt processing status
  • POST /receipts/correction — correction receipt

The response to POST /receipts returns an id — the internal task identifier. The receipt itself is not in the response; you need to poll GET /receipts/{id}.

Receipt Structure

$receipt = [
    'external_id' => 'order-' . $orderId . '-' . time(),
    'receipt'     => [
        'client'  => [
            'email' => $customerEmail, // email or phone required
        ],
        'company' => [
            'email'          => $shopEmail,
            'sno'            => 'osn', // osn, usn_income, usn_income_outcome
            'inn'            => $inn,
            'payment_address' => $siteUrl,
        ],
        'items'  => $this->buildItems($payment),
        'payments' => [
            [
                'type'  => 2, // 1-cash, 2-electronic
                'sum'   => $payment->getSum(),
            ],
        ],
        'total' => $payment->getSum(),
    ],
    'timestamp' => date('d.m.Y H:i:s'),
    'type'      => 'sell', // sell, sell_return
    'url'       => $callbackUrl,
];

The url field is the callback address after fiscalisation. CloudKassir will send a POST with the receipt data: fn, fd, fpd, QR code. This is more convenient than polling if you have a public IP address.

Building Receipt Line Items

private function buildItems(\Bitrix\Sale\Payment $payment): array
{
    $order = $payment->getOrder();
    $items = [];

    foreach ($order->getBasket() as $basketItem) {
        $items[] = [
            'name'         => mb_substr($basketItem->getField('NAME'), 0, 128),
            'price'        => $basketItem->getPrice(),
            'quantity'     => $basketItem->getQuantity(),
            'sum'          => $basketItem->getFinalPrice(),
            'payment_method' => 'full_payment', // prepayment / full payment
            'payment_object' => 'commodity',     // goods, service, work
            'vat'          => $this->getVatTag($basketItem->getField('VAT_RATE')),
        ];
    }

    if ($order->getDeliveryPrice() > 0) {
        $items[] = [
            'name'           => 'Delivery',
            'price'          => $order->getDeliveryPrice(),
            'quantity'       => 1.0,
            'sum'            => $order->getDeliveryPrice(),
            'payment_method' => 'full_payment',
            'payment_object' => 'service',
            'vat'            => 'none',
        ];
    }

    return $items;
}

The name length is limited to 128 characters — mb_substr is mandatory. The vat field accepts: none, vat0, vat10, vat110, vat20, vat120. Mapping from the Bitrix VAT rate to a CloudKassir string:

private function getVatTag(?float $vatRate): string
{
    return match(true) {
        $vatRate === null || $vatRate == 0 => 'none',
        $vatRate == 0.1  => 'vat10',
        $vatRate == 0.2  => 'vat20',
        default          => 'none',
    };
}

Bitrix Payment System Handler

The integration is implemented as a handler in /local/php_interface/include/sale_payment/cloudkassir/. The class extends \Bitrix\Sale\PaySystem\ServiceHandler.

The receipt is sent in the processRequest() method — after receiving confirmation from the payment system (bank). Not when the order is created, but specifically after confirming the fact of payment.

public function processRequest(
    \Bitrix\Sale\Payment $payment,
    \Bitrix\Main\Request $request
): \Bitrix\Sale\PaySystem\ServiceResult {
    $result = new \Bitrix\Sale\PaySystem\ServiceResult();

    // First mark the payment as paid
    $result->setOperationType(\Bitrix\Sale\PaySystem\ServiceResult::MONEY_COMING);

    // Then send the receipt
    $this->sendReceipt($payment);

    return $result;
}

Sending the receipt before payment confirmation is a violation of 54-FZ: the receipt must be generated at the moment of settlement.

Callback and Saving Fiscal Data

When a callback is received from CloudKassir (after successful fiscalisation), save the data to the order properties:

public function handleCallback(array $callbackData): void
{
    $orderId = $this->extractOrderId($callbackData['external_id']);
    $order = \Bitrix\Sale\Order::load($orderId);

    $propCollection = $order->getPropertyCollection();
    $propCollection->getItemByOrderPropertyCode('CLOUDKASSIR_FN')
        ->setValue($callbackData['fn']);
    $propCollection->getItemByOrderPropertyCode('CLOUDKASSIR_FD')
        ->setValue($callbackData['fd']);
    $propCollection->getItemByOrderPropertyCode('CLOUDKASSIR_FPD')
        ->setValue($callbackData['fpd']);

    $order->save();
}

The order properties CLOUDKASSIR_FN, CLOUDKASSIR_FD, and CLOUDKASSIR_FPD are created manually in the admin panel before launching the integration.

Refunds: Type sell_return

When processing a payment refund, a receipt with type: sell_return is submitted. The line item composition must match the original receipt. CloudKassir does not automatically link receipts by ID — the correctness of the line items is your responsibility.

For partial refunds (only some items returned) — only the returned items are passed in items with their actual quantities and amounts.

Specifics When Working with Prepayments

If the store accepts prepayments (50% at order, 50% at delivery), two receipts must be sent:

  1. On the first payment: line items with payment_method: prepayment (or advance), type sell
  2. When closing the settlement: line items with payment_method: full_payment, type sell

This is a requirement of 54-FZ. CloudKassir supports it; Bitrix does not out of the box. The two-receipt logic must be implemented custom, based on order statuses and payment type.

Testing

CloudKassir provides a test environment: https://demo.cloudkassir.ru. Test credentials are issued upon registration. In test mode, receipts are not transmitted to the tax authority — you can safely debug the request structure.

Timeline

Scope Duration
Income + refund, Basic Auth 3–4 days
+ Callback handler + saving fiscal data +1 day
+ Prepayment scheme (two receipts) +2 days