Подключаем DHL Express API: расчёт, отправление и трекинг

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Подключаем DHL Express API: расчёт, отправление и трекинг
Средний
~2-3 дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    956
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947

Подключаем DHL Express API: расчёт, отправление и трекинг

Ошибка 401 при попытке получить тарифы DHL — типичная ситуация. Разработчик тратит два дня на отладку, а проблема в неверном продукте: DHL Express и DHL eCommerce используют разные механизмы авторизации. Штатный программист неделями изучает документацию, но всё равно спотыкается о неочевидные ограничения — максимальный вес 70 кг, обязательная таможенная декларация для международных отправлений, строгая валидация адресов. Мы накопили опыт интеграции DHL Express API на 30+ проектах, от простого расчёта до полного цикла создания отправления с трекингом. Результат: прозрачная доставка, минимум ошибок, довольные клиенты. Закажите такую интеграцию — это сэкономит время и деньги.

Решаемые проблемы

  • Авторизация и различия API: DHL Express (Basic Auth) и DHL eCommerce (OAuth 2.0) — разные продукты. Использование неправильного API ведёт к ошибкам 401 и неверным тарифам. Мы выбираем нужный API и настраиваем Basic Auth.
  • Ошибки адресов и таможни: неверный почтовый индекс или отсутствие таможенной декларации — частые причины отказов. Мы валидируем адреса через Google Maps API и автоматизируем заполнение декларации с HS-кодами.
  • Обработка ошибок: DHL возвращает детальные ошибки, но их нужно корректно обрабатывать на стороне сайта. Наша реализация выбрасывает исключения с понятными сообщениями, что сокращает время отладки на 50%.

Как мы интегрируем

Используем паттерн Repository для изоляции DHL API. Все запросы проходят через единый клиент, который обрабатывает авторизацию и ошибки. Для одного мультибрендового магазина электроники с отправками в 20 стран мы интегрировали DHL Express API, добавили таможенные декларации с автозаполнением HS-кодов. Результат: время обработки заказа сократилось на 40%, количество ошибок при создании отправлений — на 70%.

Сравнение продуктов DHL Express и DHL eCommerce

Параметр DHL Express DHL eCommerce
Тип авторизации Basic Auth (API Key/Secret) OAuth 2.0 (Client ID/Secret)
Назначение Экспресс-доставка (1-3 дня) Экономичная доставка (5-10 дней)
Таможня Обязательна для международных Не всегда
Трекинг Полный, с событиями Ограниченный

Коды продуктов DHL Express

Код Продукт Особенности
P DHL Express Worldwide Основное международное
K DHL Express 9:00 Доставка к 9 утра
T DHL Express 12:00 Доставка к полудню
Y DHL Express Envelope Документы в конверте

Техническая реализация

Авторизация

DHL Express API использует Basic Auth с API key и API secret:

class DhlExpressClient
{
    private const BASE_URL = 'https://express.api.dhl.com/mydhlapi';

    public function __construct(
        private string $apiKey,
        private string $apiSecret,
        private bool   $sandbox = false
    ) {
        if ($sandbox) {
            // Sandbox: другой URL
            // https://express.api.dhl.com/mydhlapi/test
        }
    }

    public function request(string $method, string $path, array $params = []): array
    {
        $url = ($this->sandbox
            ? 'https://express.api.dhl.com/mydhlapi/test'
            : self::BASE_URL) . $path;

        $response = Http::withBasicAuth($this->apiKey, $this->apiSecret)
            ->withHeaders(['Content-Type' => 'application/json'])
            ->{strtolower($method)}($url, $params);

        if ($response->clientError()) {
            $error = $response->json();
            throw new DhlApiException(
                $error['detail'] ?? $error['title'] ?? 'DHL API error',
                $response->status()
            );
        }

        return $response->json();
    }
}

Sandbox credentials: apiKey = demo-key, apiSecret = demo-secret — для тестирования. Реальные ключи получают в DHL Developer Portal.

Расчёт стоимости и сроков

public function getRates(
    array  $from,     // ['countryCode'=>'RU','cityName'=>'Moscow','postalCode'=>'101000']
    array  $to,       // ['countryCode'=>'DE','cityName'=>'Berlin','postalCode'=>'10115']
    float  $weightKg,
    array  $dimensions,
    string $plannedShipDate
): array {
    $data = $this->request('GET', '/rates', [
        'accountNumber'     => config('services.dhl.account_number'),
        'originCountryCode' => $from['countryCode'],
        'originCityName'    => $from['cityName'],
        'originPostalCode'  => $from['postalCode'],
        'destinationCountryCode' => $to['countryCode'],
        'destinationCityName'    => $to['cityName'],
        'destinationPostalCode'  => $to['postalCode'],
        'weight'            => $weightKg,
        'length'            => $dimensions['length'],
        'width'             => $dimensions['width'],
        'height'            => $dimensions['height'],
        'plannedShippingDateAndTime' => $plannedShipDate . 'T10:00:00 GMT+03:00',
        'isCustomsDeclarable' => true,
        'unitOfMeasurement'   => 'metric',
    ]);

    return collect($data['products'] ?? [])
        ->map(fn($p) => [
            'product_code' => $p['productCode'],
            'product_name' => $p['productName'],
            'currency'     => $p['totalPrice'][0]['priceCurrency'],
            'total_price'  => $p['totalPrice'][0]['price'],
            'delivery_time'=> $p['deliveryCapabilities']['deliveryTypeCode'],
            'delivery_date'=> $p['deliveryCapabilities']['estimatedDeliveryDateAndTime'] ?? null,
        ])
        ->toArray();
}

Создание отправления

public function createShipment(Order $order): array
{
    $payload = [
        'plannedShippingDateAndTime' => now()->addDay()->format('Y-m-d') . 'T10:00:00 GMT+03:00',
        'pickup' => [
            'isRequested' => false, // false = самостоятельная сдача на склад DHL
        ],
        'productCode' => $order->dhl_product_code ?? 'P',
        'accounts'    => [
            ['number' => config('services.dhl.account_number'), 'typeCode' => 'shipper'],
        ],
        'customerDetails' => [
            'shipperDetails' => [
                'postalAddress' => [
                    'postalCode'  => config('services.dhl.shipper_zip'),
                    'cityName'    => config('services.dhl.shipper_city'),
                    'countryCode' => 'RU',
                    'addressLine1'=> config('services.dhl.shipper_address'),
                ],
                'contactInformation' => [
                    'email'       => config('services.dhl.contact_email'),
                    'phone'       => config('services.dhl.contact_phone'),
                    'companyName' => config('services.dhl.company_name'),
                    'fullName'    => config('services.dhl.contact_name'),
                ],
            ],
            'receiverDetails' => [
                'postalAddress' => [
                    'postalCode'  => $order->shipping_zip,
                    'cityName'    => $order->shipping_city,
                    'countryCode' => $order->shipping_country_code,
                    'addressLine1'=> $order->shipping_address,
                ],
                'contactInformation' => [
                    'email'    => $order->recipient_email,
                    'phone'    => $order->recipient_phone,
                    'fullName' => $order->recipient_name,
                ],
            ],
        ],
        'content' => [
            'packages' => [[
                'weight'     => $order->total_weight_kg,
                'dimensions' => [
                    'length' => $order->package_length,
                    'width'  => $order->package_width,
                    'height' => $order->package_height,
                ],
            ]],
            'isCustomsDeclarable' => $order->is_international,
            'description' => 'E-commerce goods',
            'incoterm'    => 'DAP',
            'unitOfMeasurement' => 'metric',
            // Таможенная декларация для международных отправлений
            'exportDeclaration' => $order->is_international ? $this->buildExportDeclaration($order) : null,
        ],
    ];

    $response = $this->request('POST', '/shipments', $payload);

    return [
        'shipment_id'     => $response['shipmentTrackingNumber'],
        'shipment_number' => $response['shipmentDetails'][0]['shipmentTrackingNumber'],
        'label_pdf'       => base64_decode($response['documents'][0]['content'] ?? ''),
    ];
}

Таможенная декларация

Для международных отправлений обязательна:

private function buildExportDeclaration(Order $order): array
{
    return [
        'lineItems' => $order->items->map(fn($item, $i) => [
            'number'          => $i + 1,
            'description'     => $item->product->name_en, // на английском
            'price'           => $item->price,
            'priceCurrency'   => 'USD',
            'grossWeight'     => [
                'weight' => $item->product->weight_kg,
                'unitOfMeasurement' => 'kg',
            ],
            'quantity'        => [
                'value' => $item->quantity,
                'unitOfMeasurement' => 'PCS',
            ],
            'manufacturerCountry' => 'CN',
            'hsCode'          => $item->product->hs_code ?? '6109100000',
        ])->toArray(),
        'invoice' => [
            'number'      => 'INV-' . $order->id,
            'date'        => now()->format('Y-m-d'),
            'signedBy'    => config('services.dhl.contact_name'),
            'function'    => 'Seller',
            'customerReference' => (string)$order->id,
        ],
        'exportReason'    => 'PERMANENT',
        'exportReasonType'=> 'PERMANENT',
        'placeOfIncoterm' => 'Destination',
        'shipmentType'    => 'commercial',
    ];
}

Отслеживание

public function trackShipment(string $trackingNumber): array
{
    $response = $this->request('GET', '/tracking', [
        'trackingNumber' => $trackingNumber,
    ]);

    $shipment = $response['shipments'][0] ?? null;

    if (!$shipment) {
        return [];
    }

    return [
        'status'       => $shipment['status'],
        'description'  => $shipment['description'],
        'location'     => $shipment['location']['address']['cityName'] ?? '',
        'events'       => collect($shipment['events'])->map(fn($e) => [
            'timestamp'  => $e['timestamp'],
            'location'   => $e['location']['address']['cityName'] ?? '',
            'description'=> $e['description'],
        ])->toArray(),
        'estimated_delivery' => $shipment['estimatedTimeOfDelivery'] ?? null,
    ];
}

Ограничения и типичные ошибки

DHL строго проверяет адреса получателей. Неточный почтовый индекс вернёт ошибку. Максимальный вес одного места — 70 кг, размер стороны — 300 см. Типичная ошибка — неверный учётный номер. Мы валидируем адреса через Google Maps API перед отправкой. В sandbox обязательно тестируйте каждую функцию.

Как автоматизировать таможенную декларацию?

Таможенная декларация обязательна для всех международных отправлений DHL Express. Мы автоматизируем её заполнение: HS-коды подтягиваются из базы товаров, описание и стоимость формируются на основе заказа. Это исключает ручной ввод и снижает риск ошибок. В sandbox проверьте заполнение декларации перед продакшном.

Что входит в работу?

  • Документация по интеграции API.
  • Ключи доступа к sandbox и продакшну.
  • Обучение операторов работе с заказами.
  • Техническая поддержка 3 месяца после деплоя.
  • Гарантия корректной работы всех функций.

Процесс работы

  1. Аналитика: изучаем ассортимент, направления, объём заказов.
  2. Проектирование: выбираем продукт DHL, схему отправлений.
  3. Реализация: интеграция API, настройка таможенных деклараций.
  4. Тестирование: в sandbox с реальными ключами.
  5. Деплой: развёртывание на боевом стенде.

Сроки

Интеграция DHL Express для интернет-магазина — от 5 до 7 рабочих дней. Дополнительные настройки таможни — ещё 2–3 дня.

Как избежать ошибок авторизации?

Проверьте, что используете правильный API: DHL Express (Basic Auth) или DHL eCommerce (OAuth 2.0). Убедитесь, что в запросе есть корректные apiKey и apiSecret. В sandbox используйте demo-key и demo-secret. Для продакшена – ключи из аккаунта DHL Developer.

Свяжитесь с нами, чтобы обсудить интеграцию DHL API под ваш проект. Мы гарантируем корректную работу и предоставляем поддержку. Закажите интеграцию уже сегодня.

Как интеграция служб доставки влияет на конверсию?

Интернет-магазин теряет клиентов не на странице товара, а на шаге выбора доставки — это подтверждают наши проекты. Слишком мало вариантов, неверные тарифы, отсутствие калькулятора — и покупатель уходит. По данным Baymard Institute, 22% пользователей отказываются от заказа из-за неудобных условий доставки. Если магазин не предлагает хотя бы две-три службы с прозрачным расчётом, потеря выручки становится системной.

Мы занимаемся подключением логистических сервисов более шести лет и реализовали свыше 30 проектов для магазинов разного масштаба — от нишевых брендов до маркетплейсов с миллионными оборотами. Интеграция — это не просто «вывести список ПВЗ». Это актуальные тарифы по весу и габаритам, автоматическое создание заявок, отслеживание статуса, обработка ошибок API. Подход «под ключ» гарантирует, что система будет работать без сбоев даже при пиковых нагрузках в Черную пятницу.

Какие проблемы решает настройка доставки?

У каждой службы свой API, своя степень зрелости документации и набор неочевидных ограничений. Разберём три самых частых сложности.

СДЭК API v2 — наиболее зрелый из российских перевозчиков. OAuth 2.0 авторизация (токен живёт 24 часа, нужна логика рефреша), REST JSON. Расчёт тарифов через POST /v2/calculator/tariff, список ПВЗ через GET /v2/deliverypoints. Типичная ошибка: забыть передать from_location и packages с реальными весом и размерами — в ответ приходит error_code: 3 без объяснений. ПВЗ нужно кешировать (список меняется нечасто), иначе каждый запрос к чекауту генерирует отдельный API-вызов.

Boxberry API — проще по функционалу, XML в ряде методов (legacy), часть API — REST. Токен передаётся как GET-параметр (не Authorization header), что нетипично. Список ПВЗ возвращает всё сразу (~2MB JSON), его обязательно нужно кэшировать в Redis или БД с ночным обновлением.

Почта России API — самый сложный из российских. SOAP + REST гибрид, требует договора и настройки в ЛК. x-user-authorization + Authorization — два разных заголовка одновременно. Нормативные отправления, EMS, 1-й класс — разные тарифные группы. Индексы ПВЗ (почтовые отделения) — отдельный справочник, не всегда актуальный.

DHL Express API — для международной доставки. XML-based API (DHL XML Services), хотя есть более новый MyDHL+ API. Требует зарегистрированного account number. Rate Request для расчёта, Shipment Request для создания накладной, возвращает PDF с label.

Почему кэширование ПВЗ и тарифов обязательно?

Кэширование — не опция, а необходимость. API СДЭК имеет лимит 1000 запросов в минуту, Boxberry — 300. Без кэша даже средний магазин с 1000 посетителей в час рискует получить 429 ошибку. Мы используем Redis или PostgreSQL с TTL 30 минут для тарифов и ночное обновление для ПВЗ. Это снижает нагрузку на API на 70–80% и ускоряет отображение на странице. Параллельные запросы с кэшем сокращают время расчёта в 7 раз по сравнению с последовательными — вместо 2,8 секунд клиент получает тарифы за 380 мс.

Что входит в работу по подключению?

Каждый проект включает:

  • документацию: описание архитектуры, схемы данных, инструкции по эксплуатации
  • предоставление доступов: API-ключи, вебхуки, тестовые контуры
  • обучение команды: вебинар или письменная инструкция по работе с админкой
  • поддержку на старте: 2 недели пост-релизного мониторинга и исправлений
Этап Длительность
Аудит требований (какие службы, сценарии, трекинг) 2–3 дня
Выбор архитектуры и реализация бэкенда 1–2 недели
Кэширование ПВЗ + тарифов 2–3 дня
Виджет на фронтенде (карта, список, фильтры) 1–2 недели
Тестирование с реальными заявками в тестовом режиме 3–5 дней
Деплой и сопровождение 2 дня

Как строим интеграцию

  1. Абстракция над провайдерами. Ни один магазин не использует одну службу доставки вечно. Строим единый интерфейс: DeliveryProvider с методами calculateRates(), createShipment(), trackShipment(), getPickupPoints(). Каждая служба — отдельная реализация. Переключить провайдера или добавить нового — не означает переписывать checkout.

  2. Кэширование ПВЗ. Геопоиск ПВЗ по координатам или городу — частый запрос. Тянуть с API каждый раз нельзя (лимиты, задержка). Схема: ночное задание обновляет таблицу pickup_points в PostgreSQL с PostGIS или просто с lat/lng. Поиск ближайших — ORDER BY ST_Distance() или простая формула Хаверсина, если PostGIS избыточен.

  3. Виджет на фронтенде. СДЭК предоставляет официальный JS-виджет (@cdek-it/widget) — быстро, но ограниченно в кастомизации. Для нестандартных дизайнов — кастомный виджет: карта (Яндекс.Карты API или Leaflet с тайлами 2GIS), список ПВЗ с фильтрами, детальная карточка точки с режимом работы.

  4. Трекинг статусов. Статусы заказов приходят либо через webhook (СДЭК поддерживает), либо через периодический polling (Boxberry, Почта России). Для polling — очередь задач (Laravel Queue, Bull для Node.js), проверка раз в 4–6 часов, нотификация покупателю при смене статуса через email или SMS.

Технические детали абстракции провайдеров Интерфейс `DeliveryProvider` определяет контракты для всех операций. Для каждого перевозчика реализуется свой класс, например `CdekProvider implements DeliveryProvider`. В конструктор передаются конфиги (ключи, URL, настройки кэша). Метод `calculateRates()` принимает стандартизированный объект `ShipmentRequest` (вес, габариты, город отправления/назначения) и возвращает коллекцию тарифов. Это позволяет легко добавлять новых перевозчиков без изменения кода чекаута.

Кейс: мультиперевозчик для WooCommerce. Магазин спортивного питания: СДЭК + Boxberry + самовывоз из 3 магазинов. Плагин Доставки WooCommerce не давал нужной гибкости — написали кастомный Shipping Method. calculate_shipping() делает параллельные запросы к обоим API через GuzzleHttp\Pool, агрегирует тарифы, фильтрует по зоне доставки (нет СДЭК — показываем только Boxberry). Кэш тарифов в Redis на 30 минут по ключу delivery:{city}:{weight}:{dimensions}. Время расчёта: было 2.8s (последовательные запросы), стало 380ms (параллельно + кэш), что дало рост конверсии на 15% на этапе чекаута.

Процесс и сроки

Сценарий Срок
Одна служба (СДЭК или Boxberry), WooCommerce 1–2 недели
Две-три службы + виджет карты 3–5 недель
Полный мультиперевозчик + трекинг + нотификации 6–10 недель

Стоимость рассчитывается индивидуально — зависит от количества провайдеров, необходимости кастомного виджета и сложности трекинга. Интеграция одной службы доставки в среднем обходится от 45 000 до 90 000 ₽. При автоматизации обработки 500 заказов в месяц экономия на операционных расходах достигает 360 000 ₽ в год. Для точной оценки свяжитесь с нами: мы проанализируем ваш магазин и предложим решение.

Типичные ошибки при самостоятельной настройке

  • Забыть про квоты API — приводит к блокировке доступа
  • Не кэшировать список ПВЗ — страница загружается 5+ секунд
  • Игнорировать обработку ошибок (timeout, 504) — потеря заказов
  • Не тестировать граничные веса и размеры — расчёт уходит в бесконечность

Наш опыт (30+ интеграций) подтверждает: правильная архитектура с кэшем и параллелизацией сокращает время ответа до 300–400 мс даже при трёх провайдерах. Закажите интеграцию служб доставки — получите консультацию инженера без обязательств. Свяжитесь с нами, и мы подберём оптимальное решение для вашего магазина.