Bitrix Integration with Kontur.Accounting: Automate Data Exchange

Manual data transfer between Bitrix and accounting consumes time and leads to errors. We automate the exchange via Kontur.Accounting REST API so documents reach the records without delays. Our team delivers turnkey integration—from audit to launch and ongoing support.

Our competencies:

Frequently Asked Questions

Manual data transfer slows down business

A small online store sells through Bitrix, while the accountant keeps records in Kontur.Accounting. Every month, the accountant manually transfers sales data, invoices, and payments — taking 2–4 hours of monotonous work. Copying errors lead to discrepancies: one extra digit in the TIN and the tax office demands clarifications. We've encountered cases where this delayed reporting, and fines for incorrect data reached 20% of the transaction amount. The solution is to set up automatic exchange via the Kontur.Accounting REST API. This eliminates the human factor, reduces order processing time to seconds, and ensures documents reach the accounting department without delays. Our team has over 5 years of experience integrating Bitrix with external services and has completed more than 30 such projects. Automation can save up to $14k–20k per year on accounting labor costs, as well as reduce the risk of fines. We offer turnkey integration: from auditing the current scheme to launch and monitoring. Request a consultation — we'll assess your project and provide timelines.

Kontur.Accounting API for accounting automation

Kontur.Accounting provides a REST API documentation. Authorization via OAuth 2.0 or API key (depends on the tariff). Available entities: counterparties, contracts, documents (invoices, acts, bills), bank operations, expense items. For an online store, key operations are: creating and searching for counterparties by TIN, creating sales documents (invoices, acts), and recording payments. Automation is 60 times faster than manual entry — 2–5 seconds versus 2–5 minutes per order. The API has a limit of 100 requests per minute, which is sufficient even for high-traffic stores. For network errors, we use retry with exponential backoff to guarantee delivery of each document. We also support CommerceML format for data exchange and ensure compliance with 54-FZ for fiscal documents.

Authorization in the API

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, you need to ensure the counterparty exists in Kontur.Accounting. A typical mistake is trying to create a document without prior synchronization. We use search by TIN: if the counterparty already exists, use its ID; if not, create a new one. This prevents duplicate records.

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

    // Search by TIN
    $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 sales document

When the order status changes to "Shipped", create an invoice in Kontur.Accounting. Use the OnSaleStatusOrder event.

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 properties
    $order->setField('COMMENTS', $order->getField('COMMENTS') . "\nKontur document ID: " . $document['id'] );
    $order->save();
}

Recording payment

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 relations

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
);

How to set up integration in 5 steps?

  1. Obtain an API key in the Kontur.Accounting personal account.
  2. Install the PHP client (code above) on the server with Bitrix.
  3. Map the order custom fields to the API entities.
  4. Register event handlers for OnSaleStatusOrder and OnSalePaymentPaid.
  5. Conduct a test synchronization on a staging environment and launch monitoring.

Additionally, a notification system is configured: in case of synchronization errors, an alert is sent via email or Telegram. This allows for quick response to failures.

What is included in the integration work

Stages and deliverables
Stage Duration Deliverable
Analysis and design 3–5 days Exchange scheme documentation, field mapping
API client development 5–7 days PHP class with error handling and retries
Counterparty synchronization 2–3 days Search/create by TIN, duplicate check
Document creation 3–5 days Invoices, acts, bills based on orders
Payment and return recording 2–3 days Payment processing
Testing and launch 3–5 days Tests on staging, error monitoring
Training and handover 2 days Employee training, access to monitoring

Total: from 18 to 28 working days (3–5 weeks). Cost is calculated individually — depends on business logic complexity and number of statuses.

After the project, you receive: full documentation of the exchange scheme, API keys and access setup, training for accountants, and 1 month of free support after launch.

Comparison: manual processing vs automation

Parameter Manual work Automation with API
Time to transfer one order 2–5 minutes 2–5 seconds
Error probability 5–10% <0.1%
Accountant's time per month 8–16 hours 0 minutes
Transfer delay From 1 day Instant
Fines for document errors Risk up to 20% of amount Minimized

Why trust us with the integration

We don't just write code — we design an architecture that will work for years. We guarantee that documents will not be lost: we use a queue with retries and log all operations. Our experience includes over 30 integrations of Bitrix with accounting systems (1C, Kontur, MoySklad). Want to estimate how much your business can save? Contact us — we will analyze your current document flow and propose a solution. Order the integration — and forget about manual data transfer.