1C-Bitrix integration with the Business Lines delivery service

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 Delovye Linii Delivery Service

Delovye Linii is a major transport company with a terminal network across Russia. Like PEK, it specializes in cargo transportation: from small parcels to pallet shipments. A notable characteristic — in a number of regions it is the only alternative to Russian Post for delivery with reasonable timelines to industrial centers.

The Delovye Linii API is REST with JWT authorization. Documentation is in Russian and covers the main operations.

Delovye Linii API: Structure

Base URL: https://api.dellin.ru/v3/. Authorization is two-step: first obtain a session token via /v3/auth/login.json, then use it in the Cookie: session=TOKEN header or as a parameter.

private function getSession(): string
{
    $cacheKey = 'dellin_session_' . md5($this->appKey);
    $cached = \Bitrix\Main\Data\Cache::createInstance();

    if ($cached->startDataCache(3600 * 8, $cacheKey, '/dellin')) {
        $response = $this->httpPost('/v3/auth/login.json', [
            'appkey'   => $this->appKey,
            'login'    => $this->login,
            'password' => $this->password,
        ]);
        $session = $response['data']['sessionID'] ?? '';
        $cached->endDataCache(['session' => $session]);
    }

    return $cached->getVars()['session'];
}

The session lives 8+ hours. Cache for 8 hours to avoid re-authorizing on every cost calculation.

Cost Calculation

private function calcCost(
    string $fromCity,
    string $toCity,
    float $weightKg,
    float $volumeM3
): float {
    $response = $this->apiPost('/v3/calculator.json', [
        'appkey'          => $this->appKey,
        'sessionID'       => $this->getSession(),
        'delivery'        => [
            'deliveryType' => ['type' => 'auto'],
            'arrival'      => ['variant' => 'address'],
            'dispatch'     => ['variant' => 'terminal'],
        ],
        'cargo'           => [
            'quantity'       => 1,
            'weight'         => $weightKg,
            'volume'         => $volumeM3,
            'totalEnvelopesWeight' => 0,
        ],
        'members'         => [
            'from' => ['terminalID' => $this->findTerminalId($fromCity)],
            'to'   => ['city'       => $toCity],
        ],
    ]);

    return (float)($response['data']['price'] ?? 0);
}

The parameter delivery.dispatch.variant: terminal means the store will deliver the cargo to the terminal itself. arrival.variant: address — delivery to the customer's door. Variant combinations affect the price: terminal-to-terminal is cheaper, address-to-address is more expensive.

Finding a Terminal by City

public function findTerminalId(string $cityName): string
{
    $response = $this->apiPost('/v3/public/terminals.json', [
        'appkey' => $this->appKey,
    ]);

    foreach ($response['data']['terminals'] ?? [] as $terminal) {
        if (mb_stripos($terminal['city']['name'], $cityName) !== false) {
            return $terminal['id'];
        }
    }

    return '';
}

The terminal list is large — cache the search result for one day.

Order Creation

public function createOrder(\Bitrix\Sale\Shipment $shipment): string
{
    $order = $shipment->getOrder();
    $props = $order->getPropertyCollection();

    $payload = [
        'appkey'    => $this->appKey,
        'sessionID' => $this->getSession(),
        'delivery'  => [
            'deliveryType' => ['type' => 'auto'],
            'dispatch'     => ['variant' => 'terminal'],
            'arrival'      => [
                'variant'  => 'address',
                'address'  => [
                    'search' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
                ],
            ],
        ],
        'cargo'     => $this->buildCargo($shipment),
        'members'   => [
            'from' => ['terminalID' => $this->getOption('FROM_TERMINAL_ID')],
            'to'   => [
                'contactPersons' => [[
                    'name'  => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
                    'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
                ]],
            ],
        ],
        'payment'   => [
            'type'   => 'cash',
            'payer'  => 'receiver', // recipient pays for delivery (cash on delivery)
        ],
    ];

    $response = $this->apiPost('/v3/orders.json', $payload);
    return (string)($response['data']['orderID'] ?? '');
}

The parameter payment.payer: receiver — delivery is paid by the recipient. sender — paid by the sender (store). The choice depends on the store's business model.

Order Tracking

public function getOrderState(string $orderId): array
{
    $response = $this->apiPost('/v3/orders/state.json', [
        'appkey'    => $this->appKey,
        'sessionID' => $this->getSession(),
        'orders'    => [['orderID' => $orderId]],
    ]);

    $state = $response['data'][0] ?? [];
    return [
        'status'       => $state['orderState']['name'] ?? '',
        'deliveryDate' => $state['deliveryDate'] ?? '',
    ];
}

Delovye Linii does not support webhooks for tracking. A 1C-Bitrix agent polls active shipment statuses every 3–4 hours.

Specifics for Oversized Goods

Delovye Linii supports pallet shipments. For furniture or building materials stores, shipments need to be split into multiple units with individual dimensions. The cargo.oversizedWeight field is used for non-standard units (> 80 kg or > 3 m in length).

Timelines

Scope Timeline
Authorization + calculation + terminal mapping 3–4 days
+ Order creation + tracking +2 days
+ Dimensional calculation + pallets +1 day