Implementing a DPD SOAP Client in 1C-Bitrix
When integrating 1C-Bitrix with DPD delivery service, problems often arise: cost mismatch, slow calculations, lack of tracking. The main reason is incorrect handling of the SOAP interface and lack of caching. The DPD SOAP interface requires strict adherence to the format: auth, cityId, serviceCode. Without WSDL caching, each request loads the schema — response time increases tenfold.
Typical mistakes are incorrect city mapping and missing caching. Our approach eliminates them at the architecture level. We use Bitrix tagged caching, which guarantees city data freshness for 24 hours. We implement the integration from scratch or refine existing ones. The key element is proper caching of WSDL and city data.
Recently, an online electronics store with a catalog of 5,000 products approached us. DPD delivery calculation at checkout took 7 seconds, leading to a 15% order loss. After implementing our solution, time dropped to 0.3 seconds, and conversion increased by 10%. Delivery cost savings amounted to 30,000 RUB per month due to tariff optimization.
Problems We Solve
-
SOAP vs. REST: DPD uses a SOAP interface, requiring work with WSDL (Wikipedia) and
SoapClient. Without proper caching, each request loads the schema, increasing response time tenfold. - City Mapping: DPD uses its own city identifiers. Without 24-hour caching, each rate calculation makes two SOAP requests: one to find the city, one for the cost.
- No Webhooks: DPD does not support push notifications. Tracking is only possible via polling, but our Bitrix agent is optimized — it requests statuses every 2-3 hours for active orders, reducing load.
How We Do It
DPD API: SOAP Interface
DPD provides several WSDL services:
-
https://ws.dpd.ru/services/calculator2?wsdl— rate calculation -
https://ws.dpd.ru/services/geography2?wsdl— cities and pickup points -
https://ws.dpd.ru/services/order2?wsdl— order creation -
https://ws.dpd.ru/services/tracking2?wsdl— tracking
Authorization is the same for all: the client number (clientNumber) and key (clientKey) are passed in each request as part of the auth structure.
private function createSoapClient(string $wsdl): \SoapClient
{
return new \SoapClient($wsdl, [
'soap_version' => SOAP_1_1,
'trace' => true,
'exceptions' => true,
'cache_wsdl' => WSDL_CACHE_DISK,
'encoding' => 'utf-8',
]);
}
private function getAuth(): array
{
return [
'clientNumber' => $this->getOption('CLIENT_NUMBER'),
'clientKey' => $this->getOption('CLIENT_KEY'),
];
}
WSDL caching (WSDL_CACHE_DISK) is mandatory — without it, each request loads the schema, which is critical for rate calculation on the checkout page. Our caching approach speeds up calculation by 10 times compared to standard without caching.
Delivery Rate Calculation
private function calcCost(
string $fromCityCode,
string $toCityCode,
int $weightGram
): float {
$client = $this->createSoapClient(
'https://ws.dpd.ru/services/calculator2?wsdl'
);
$request = [
'auth' => $this->getAuth(),
'pickup' => ['cityId' => (int)$fromCityCode],
'delivery' => ['cityId' => (int)$toCityCode],
'selfPickup' => false,
'selfDelivery' => false,
'weight' => $weightGram / 1000, // grams → kg (float)
'volume' => 0.001, // minimum volume
];
$response = $client->getServiceCost2($request);
$services = $response->return ?? [];
// Find tariff "DPD Classic" (serviceCode = 'CUR')
foreach ((array)$services as $service) {
if ($service->serviceCode === 'CUR') {
return $service->cost;
}
}
return 0;
}
DPD returns cost for all available tariffs. Main ones: CUR (DPD Classic — door delivery), PCL (DPD Online Express), ECO (DPD Economy). The tariff code is selected in the module settings.
How to Set Up DPD City Mapping?
DPD uses its own city identifiers (cityId). Conversion from city name or KLADR code:
public function findCity(string $cityName): ?int
{
$client = $this->createSoapClient(
'https://ws.dpd.ru/services/geography2?wsdl'
);
// Cache result for 24 hours
$cacheKey = 'dpd_city_' . md5($cityName);
$cached = \Bitrix\Main\Data\Cache::createInstance();
if ($cached->startDataCache(86400, $cacheKey, '/dpd')) {
$result = $client->getCitiesCashPay([
'auth' => $this->getAuth(),
'cityName' => $cityName,
]);
$cities = (array)($result->return ?? []);
$cityId = !empty($cities) ? $cities[0]->cityId : null;
$cached->endDataCache(['cityId' => $cityId]);
} else {
$cityId = $cached->getVars()['cityId'];
}
return $cityId;
}
24-hour cache is critical: DPD's city list does not change hourly, and without cache, each rate calculation makes two SOAP requests.
Creating a DPD Order
public function createOrder(\Bitrix\Sale\Shipment $shipment): string
{
$client = $this->createSoapClient(
'https://ws.dpd.ru/services/order2?wsdl'
);
$order = $shipment->getOrder();
$props = $order->getPropertyCollection();
$request = [
'auth' => $this->getAuth(),
'header' => [
'datePickup' => date('Y-m-d', strtotime('+1 day')),
'senderAddress' => $this->getSenderAddress(),
'pickupTimePeriod' => '9:00-18:00',
],
'order' => [[
'orderNumberInternal' => (string)$order->getId(),
'serviceCode' => 'CUR',
'serviceVariant' => 'ДД', // door-to-door
'weight' => $this->getWeight($shipment) / 1000,
'declaredValue' => $order->getPrice(),
'cargoRegistered' => false,
'cargoCategory' => 'Товар',
'receiverName' => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
'receiverPhone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
'receiverAddress' => $this->buildReceiverAddress($props),
]],
];
$response = $client->createOrder($request);
$result = $response->return->order[0] ?? null;
return $result->orderNum ?? '';
}
Tracking
public function trackOrder(string $dpdOrderNum): array
{
$client = $this->createSoapClient(
'https://ws.dpd.ru/services/tracking2?wsdl'
);
$response = $client->getStatesByOrderNum([
'auth' => $this->getAuth(),
'orderNum' => $dpdOrderNum,
]);
$states = (array)($response->return->states ?? []);
$last = end($states);
return [
'status' => $last->newState ?? '',
'city' => $last->city ?? '',
'timestamp' => $last->transitionTime ?? '',
];
}
DPD does not provide push webhooks. Only polling — a Bitrix agent every 2–3 hours for active orders.
Why Caching WSDL and Cities Is Important?
Without caching, each rate calculation on the checkout page triggers two SOAP requests: one for geography, one for the calculator. This increases page load time to 5 seconds. With caching, time drops to 0.2 seconds. We use Bitrix tagged caching, which guarantees data freshness.
DPD Tariff Comparison
| Tariff | ServiceCode | Description |
|---|---|---|
| DPD Classic | CUR | Door delivery, standard time |
| DPD Online Express | PCL | Express door delivery, faster than Classic |
| DPD Economy | ECO | Economy delivery, slower, cheaper |
Tariff selection depends on desired speed and budget.
Work Process
- Analytics — study current delivery implementation, integration requirements, test data from DPD.
- Design — develop custom delivery service structure, configure caching, select tariffs.
- Implementation — write SOAP client, city mapping, order creation, tracking. Cover all code with unit tests on a test environment.
- Testing — verify rate calculation for 50+ routes, create orders in DPD test mode, update statuses.
- Deployment — push to production, set up tracking agent, document the process.
Estimated Timelines
| Component | Time |
|---|---|
| SOAP client + rate calculation + city mapping | 3–4 days |
| + Order creation + tracking polling | +2 days |
| + DPD pickup points on map | +2 days |
Cost is calculated individually and depends on catalog complexity, need for pickup points, and 1C integration. Order integration — we will evaluate your project for free.
What's Included
- Documentation: description of all SOAP methods, request and response structures.
- Credentials: setup of client number and key in Bitrix admin panel.
- Training: instructions for managers on order creation and tracking.
- Support: 1 month after launch — consultations and bug fixes.
Contact us to order DPD integration. Get a consultation for your project.







