Integration of 1C-Bitrix with SDEK 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 SDEK Delivery Service

SDEK is one of the largest logistics networks in Russia and the CIS. Integration with Bitrix covers delivery cost calculation based on rates, order creation, shipping label retrieval, and tracking. SDEK provides an official PHP SDK (cdek-sdk2/cdek-sdk2), which simplifies working with API v2, but does not eliminate the need to correctly embed this into the Bitrix architecture.

SDEK API v2: Core Principles

SDEK uses OAuth 2.0 for authorisation. A token is obtained via POST /v2/oauth/token with client_id and client_secret from the personal account. The token is valid for 3600 seconds — cache it in Bitrix cache (\Bitrix\Main\Data\Cache), do not request it on every call.

Main endpoints:

  • POST /v2/calculator/tariff — calculate cost for a single tariff
  • POST /v2/calculator/tarifflist — calculate cost for all tariffs
  • POST /v2/orders — create an order
  • GET /v2/orders?cdek_number={n} — order status
  • POST /v2/print/orders — generate a PDF shipping label

SDEK Delivery Module in Bitrix

class CdekDeliveryService extends \Bitrix\Sale\Delivery\Services\Base
{
    protected static function getClassTitle(): string
    {
        return 'SDEK';
    }

    protected function calculateConcrete(
        \Bitrix\Sale\Shipment $shipment
    ): \Bitrix\Sale\Delivery\CalculationResult {
        $result = new \Bitrix\Sale\Delivery\CalculationResult();

        $toLocation = $this->getLocationCode($shipment);
        if (!$toLocation) {
            $result->addError(new \Bitrix\Main\Error('Location could not be determined'));
            return $result;
        }

        $price = $this->calcPrice($shipment, $toLocation);
        $result->setDeliveryPrice($price);
        $result->setPeriodDescription('2–5 days');

        return $result;
    }
}

The getLocationCode() method converts a Bitrix location into an SDEK city code. The conversion is built via the b_sale_location table — by KLADR code or city name. For correct mapping, use GET /v2/location/cities?city={name}.

Cost Calculation

private function calcPrice(\Bitrix\Sale\Shipment $shipment, string $toCode): float
{
    $order = $shipment->getOrder();
    $weight = max($shipment->getWeight(), 100); // minimum 100g

    $payload = [
        'type'          => 1, // 1-online store
        'tariff_code'   => 136, // 136-door delivery
        'from_location' => ['code' => $this->getOption('FROM_LOCATION_CODE')],
        'to_location'   => ['code' => $toCode],
        'packages'      => [
            [
                'weight' => $weight,
                'length' => $this->getOption('DEFAULT_LENGTH') ?: 20,
                'width'  => $this->getOption('DEFAULT_WIDTH') ?: 20,
                'height' => $this->getOption('DEFAULT_HEIGHT') ?: 20,
            ],
        ],
        'services' => $this->getAdditionalServices($order),
    ];

    $response = $this->apiPost('/v2/calculator/tariff', $payload);
    return $response['total_sum'] ?? 0;
}

Tariff code 136 — "Parcel warehouse-to-door". For pickup point delivery, code 136 or 138 ("Parcel warehouse-to-warehouse") is used. Current tariff list: GET /v2/calculator/tarifflist.

Creating an SDEK Order

private function createCdekOrder(\Bitrix\Sale\Shipment $shipment): string
{
    $order = $shipment->getOrder();
    $propertyCollection = $order->getPropertyCollection();

    $payload = [
        'type'          => 1,
        'number'        => (string)$order->getId(),
        'tariff_code'   => 136,
        'from_location' => $this->getFromLocation(),
        'to_location'   => $this->getToLocation($propertyCollection),
        'recipient'     => [
            'name'   => $propertyCollection->getItemByOrderPropertyCode('FIO')?->getValue(),
            'phones' => [['number' => $propertyCollection->getItemByOrderPropertyCode('PHONE')?->getValue()]],
        ],
        'packages'      => $this->buildPackages($shipment),
        'comment'       => 'Order #' . $order->getId(),
    ];

    $response = $this->apiPost('/v2/orders', $payload);

    // Save the SDEK order ID to the Bitrix order properties
    $propertyCollection->getItemByOrderPropertyCode('CDEK_ORDER_UUID')
        ?->setValue($response['entity']['uuid']);

    $order->save();

    return $response['entity']['uuid'];
}

Statuses and Tracking

SDEK supports webhooks: configured in the personal account. When the SDEK order status changes, SDEK sends a POST to the specified URL. Status mapping:

SDEK Status Bitrix Order Status
RECEIVED_AT_SHIPMENT_WAREHOUSE Accepted at warehouse
READY_FOR_SHIPMENT_IN_TRANSIT_CITY Dispatched
ARRIVED_AT_DESTINATION_CITY Arrived in city
DELIVERY Handed to courier
DELIVERED Delivered
NOT_DELIVERED Not delivered

Without a public IP — poll with an agent every 2 hours for active shipments.

Pickup Point Widget on the Site

SDEK provides a JavaScript widget for selecting a pickup point on a map. The widget is called in the delivery component template and passes the selected pickup point code to a hidden form field. When creating an order, delivery_point with the pickup point code is used instead of to_location with an address.

window.open_cdek_map = function() {
    window.CDEKWidget.open({
        defaultCity: 'Moscow',
        onChoose: function(type, tariff, address) {
            document.getElementById('cdek_pvz_code').value = address.code;
            document.getElementById('cdek_pvz_name').value = address.name;
        }
    });
};

Shipping Label and Barcode

After creating an order in SDEK, a shipping label can be generated: POST /v2/print/orders with the order UUID. The response contains a link to download the PDF. Implement a button in the Bitrix order admin panel: the manager clicks "Print SDEK Label" — a PDF opens.

Timeline

Scope Duration
Cost calculation + order creation 4–5 days
+ Tracking (webhooks or polling) +2 days
+ Pickup point widget on site +2 days
+ Shipping label in admin panel +1 day