PEK in Bitrix: calculation, order creation, tracking

PEK in Bitrix: calculation, order creation, tracking PEK (First Expedition Company) is one of the key transport companies for cargo and consolidated delivery in Russia. The main specificity of integration: PEK works with cargo from 1 kg and above, the API is tailored to cargo place parameters (le

Our competencies:

Frequently Asked Questions

PEK in Bitrix: calculation, order creation, tracking

PEK (First Expedition Company) is one of the key transport companies for cargo and consolidated delivery in Russia. The main specificity of integration: PEK works with cargo from 1 kg and above, the API is tailored to cargo place parameters (length, width, height, weight of each place separately), not to the standard retail format of Bitrix. If you have an online store with large-sized items — sofas, building materials, industrial equipment — PEK often becomes the main carrier.

From our practice: we implemented integration for a chain of building materials stores — calculation became 25% more accurate, and surcharges stopped. With 5+ years of Bitrix experience and over 30 delivery projects, we guarantee a reliable solution.

PEK API features

PEK provides a REST API with authentication via Bearer token. The token is obtained via POST /v2/sign-in with login and password from the personal account. The token does not have a strict TTL (in practice it lives 24–48 hours), but it is recommended to cache it and refresh on receiving a 401.

Key endpoints:

  • POST /v2/calculator — cost and time calculation
  • POST /v2/orders — order creation
  • GET /v2/orders/{id} — order status
  • GET /v2/departments — list of PEK terminals

Base URL: https://api.pek.ru. Documentation is available in the partner's personal account.

How to set up cost calculation?

class PekDeliveryHandler extends \Bitrix\Sale\Delivery\Services\Base { protected function calculateConcrete( \Bitrix\Sale\Shipment $shipment ): \Bitrix\Sale\Delivery\CalculationResult { $result = new \Bitrix\Sale\Delivery\CalculationResult(); $token = $this->getApiToken(); $payload = $this->buildCalcPayload($shipment); $response = $this->apiPost('/v2/calculator', $payload, $token); if (empty($response['price'])) { $result->addError(new \Bitrix\Main\Error('Calculation unavailable')); return $result; } $result->setDeliveryPrice((float)$response['price']); $result->setPeriodDescription($response['period_min'] . '–' . $response['period_max'] . ' days'); return $result; } private function buildCalcPayload(\Bitrix\Sale\Shipment $shipment): array { $order = $shipment->getOrder(); return [ 'senderCityId' => (int)$this->getOption('SENDER_CITY_ID'), 'receiverCityId' => $this->getReceiverCityId($shipment), 'cargo' => $this->buildCargoPlaces($shipment), 'service' => $this->getOption('SERVICE_TYPE', 'door_door'), 'declaredValue' => round($order->getPrice(), 2), ]; } private function buildCargoPlaces(\Bitrix\Sale\Shipment $shipment): array { // PEK requires parameters of each cargo place separately $weight = max($shipment->getWeight() / 1000, 1); // g -> kg, minimum 1 kg return [ [ 'weight' => $weight, 'length' => (int)$this->getOption('DEFAULT_LENGTH', 50), 'width' => (int)$this->getOption('DEFAULT_WIDTH', 50), 'height' => (int)$this->getOption('DEFAULT_HEIGHT', 50), ], ]; } } 

Important: PEK calculates based on volumetric weight. If actual weight is less than volumetric (L×W×H / 5000 for air, / 4000 for ground), volumetric is used. For large-sized items this is critical — pass real product dimensions. PEK documentation: volumetric weight = (L×W×H)/5000 for air and /4000 for ground.

How to get cityId and not make mistakes?

PEK uses its own numeric city identifiers. City search:

public function findCityId(string $cityName): ?int { $response = $this->apiGet('/v2/city?name=' . urlencode($cityName), $this->getApiToken()); return $response[0]['id'] ?? null; } 

Alternative: download the PEK city directory and store the mapping city_name → pek_city_id in an infoblock or custom table. At project start, we recommend this approach — the city search API returns ambiguous results for localities with the same name.

Order creation and terminals

private function createPekOrder(\Bitrix\Sale\Shipment $shipment): string { $order = $shipment->getOrder(); $props = $order->getPropertyCollection(); $payload = [ 'senderCityId' => (int)$this->getOption('SENDER_CITY_ID'), 'receiverCityId' => $this->getReceiverCityId($shipment), 'cargo' => $this->buildCargoPlaces($shipment), 'service' => $this->getOption('SERVICE_TYPE', 'door_door'), 'declaredValue' => round($order->getPrice(), 2), 'sender' => [ 'company' => $this->getOption('SENDER_COMPANY'), 'contact' => $this->getOption('SENDER_CONTACT'), 'phone' => $this->getOption('SENDER_PHONE'), 'address' => $this->getOption('SENDER_ADDRESS'), ], 'receiver' => [ 'contact' => $props->getItemByOrderPropertyCode('FIO')?->getValue(), 'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(), 'address' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(), ], ]; $response = $this->apiPost('/v2/orders', $payload, $this->getApiToken()); return (string)($response['id'] ?? ''); } 

For door_terminal or terminal_door types, you need to pass the PEK terminal ID. List of terminals: GET /v2/departments. Filter by cityId. On the site, implement a dropdown list of terminals with a map — a widget or custom implementation on Leaflet/Yandex Maps.

Why is it important to pass real dimensions?

Case from our practice: a building materials store, average order weight 50–200 kg, many sheet materials. Problem during implementation: Bitrix stores shipment weight as a single number, but PEK for orders with multiple items of different sizes requires a list of cargo places with dimensions for each. We had to implement a splitting logic: each product in the infoblock has properties DELIVERY_LENGTH, DELIVERY_WIDTH, DELIVERY_HEIGHT. When forming the shipment, each item unit becomes a separate cargo place.

This increased calculation accuracy: deviation from the real cost dropped from ±30% to ±5%, savings on surcharges accounted for up to 15% of the delivery cost. Such detail is a key advantage over the standard approach that uses average weight.

Status tracking

PEK Status Meaning
accepted Accepted for transportation
in_transit In transit
arrived Arrived at destination terminal
out_for_delivery Handed to courier
delivered Delivered
returned Returned

PEK does not have webhooks — only polling. A Bitrix agent requests statuses of active shipments every 4 hours via GET /v2/orders/{id} and updates the order status in the store. Our experience shows that polling is simpler and cheaper than webhooks for low loads (up to 500 shipments per day).

Typical integration mistakes

Mistake Consequence Solution
Passing average dimensions Surcharge up to 30% Specify product properties
Wrong cityId Incorrect calculation Download full directory
No token caching API limits Cache with invalidation on 401
Ignoring volumetric weight Overpricing Account for the coefficient

What is included in turnkey work

  • Development of a delivery handler on PHP 8.1+ with full cycle: calculation → creation → tracking.
  • Setting up PEK city matching (download and mapping).
  • Generation of cargo places based on product properties (if required).
  • Integration of a terminal map on the storefront.
  • Tracking agent and customer status notifications.
  • Documentation and consultation on modifications.

Get a consultation on integration — our engineers are Bitrix certified and have 5+ years of commercial experience. Contact us to evaluate your project.

Timeline

Module Time
Cost calculation + order creation 4–5 days
+ Terminal list + map +2–3 days
+ Splitting into cargo places by product +2 days
+ Status polling + notifications +2 days

We will evaluate your project in 1 day — contact us to discuss details.