Integrating 1C-Bitrix with Kontur.Accounting

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
    1177
  • 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 Kontur.Accounting

A small online store operates without 1C: sales are managed through Bitrix, while the accountant maintains records in Kontur.Accounting. Each month, the accountant manually transfers sales data, invoices, and payments from Bitrix to Kontur.Accounting — 2–4 hours of repetitive work prone to errors. Kontur.Accounting provides a REST API that makes it possible to automate this process.

What the Kontur.Accounting API Provides

API documentation: https://api.kontur.ru/budget/v1/. Authorization via OAuth 2.0 or an API key (depends on the plan). Available entities: counterparties, contracts, documents (invoices, acts, bills), bank transactions, expense categories.

For integration with an online store, we use: creating/searching counterparties, creating sale documents (invoice or act), and recording payments.

Authorization

class KonturBukhClient
{
    private string $apiKey;
    private string $accountId; // Organization ID in Kontur.Accounting
    private string $baseUrl = 'https://api.kontur.ru/budget/v1';

    public function __construct(string $apiKey, string $accountId)
    {
        $this->apiKey    = $apiKey;
        $this->accountId = $accountId;
    }

    public function request(string $method, string $path, array $data = []): array
    {
        $url = "{$this->baseUrl}/accounts/{$this->accountId}{$path}";
        $ch  = curl_init($url);

        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                "X-Api-Key: {$this->apiKey}",
            ],
        ];

        if ($method === 'POST' || $method === 'PUT') {
            $options[CURLOPT_CUSTOMREQUEST] = $method;
            $options[CURLOPT_POSTFIELDS]    = json_encode($data);
        } elseif ($method === 'GET' && $data) {
            $url .= '?' . http_build_query($data);
            curl_setopt($ch, CURLOPT_URL, $url);
        }

        curl_setopt_array($ch, $options);
        $response = json_decode(curl_exec($ch), true);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode >= 400) {
            throw new \RuntimeException("Kontur API error {$httpCode}: " . json_encode($response));
        }

        return $response ?? [];
    }
}

Counterparty Synchronization

Before creating a document, a counterparty must exist in Kontur.Accounting. Search by tax ID — if not found, create:

public function findOrCreateContragent(\Bitrix\Sale\Order $order): string
{
    $props = $order->getPropertyCollection();
    $inn   = $props->getItemByOrderPropertyCode('INN')->getValue();
    $name  = $props->getItemByOrderPropertyCode('COMPANY')->getValue();

    // Search by tax ID
    $found = $this->client->request('GET', '/counterparties', ['inn' => $inn]);
    if (!empty($found['items'])) {
        return $found['items'][0]['id'];
    }

    // Create new
    $contragent = $this->client->request('POST', '/counterparties', [
        'name'  => $name,
        'inn'   => $inn,
        'kpp'   => $props->getItemByOrderPropertyCode('KPP')->getValue() ?? '',
        'type'  => 'LegalEntity',
    ]);

    return $contragent['id'];
}

Creating a Sale Document

When the order status changes to "Shipped", create an invoice:

AddEventHandler('sale', 'OnSaleStatusOrder', function(string $statusId, \Bitrix\Sale\Order $order) {
    if ($statusId !== 'D') return; // D = Delivering/Shipped

    $service = new KonturBukhSyncService();
    $service->createInvoiceForOrder($order);
});

public function createInvoiceForOrder(\Bitrix\Sale\Order $order): void
{
    $contragentId = $this->findOrCreateContragent($order);
    $orderNumber  = $order->getField('ACCOUNT_NUMBER');
    $items        = [];

    foreach ($order->getBasket() as $item) {
        $items[] = [
            'name'     => $item->getField('NAME'),
            'quantity' => $item->getQuantity(),
            'price'    => $item->getPrice(),
            'vatRate'  => $this->getVatRate($item), // 'none'|'vat0'|'vat10'|'vat20'
            'unit'     => 'pcs.',
        ];
    }

    $document = $this->client->request('POST', '/documents/saleinvoices', [
        'date'           => date('Y-m-d'),
        'number'         => $orderNumber,
        'counterpartyId' => $contragentId,
        'items'          => $items,
        'totalAmount'    => $order->getPrice(),
        'comment'        => 'Automatically created from order #' . $orderNumber,
    ]);

    // Save document ID in order comments
    $order->setField('COMMENTS',
        $order->getField('COMMENTS') . "\nKontur.Accounting document ID: " . $document['id']
    );
    $order->save();
}

Recording Payments

When the order payment status changes to "Paid":

AddEventHandler('sale', 'OnSalePaymentPaid', function(\Bitrix\Sale\Payment $payment) {
    $order        = $payment->getOrder();
    $documentId   = $this->getKonturDocumentId($order->getId()); // from storage

    if (!$documentId) return;

    $this->client->request('POST', "/documents/saleinvoices/{$documentId}/payments", [
        'date'           => date('Y-m-d'),
        'amount'         => $payment->getSum(),
        'paymentMethod'  => $payment->getPaySystem()->getField('CODE') === 'cash'
            ? 'Cash' : 'BankTransfer',
    ]);
});

Storing Relationships

Table local_kontur_bukh_sync:

CREATE TABLE local_kontur_bukh_sync (
    ORDER_ID     INT PRIMARY KEY,
    KB_DOC_ID    VARCHAR(100),
    SYNCED_AT    DATETIME,
    STATUS       ENUM('pending','synced','error') DEFAULT 'pending',
    ERROR_MSG    TEXT
);

Scope of Work

  • PHP client for the Kontur API with error handling
  • Searching and creating counterparties by tax ID
  • Creating sale documents on order events
  • Recording payments and processing refunds
  • Synchronization table, retry logic on errors

Timeline: 3–5 weeks for the full cycle (sale documents + payments + refunds + monitoring).