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 |







