Интеграция службы доставки Boxberry на сайт

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

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Интеграция службы доставки Boxberry на сайт
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Интеграция службы доставки Boxberry на сайт

Boxberry — сеть доставки с упором на пункты выдачи: более 15 000 точек по России. API достаточно прямолинейное: токен в заголовке или параметре, JSON в ответе, никакого OAuth. Это упрощает интеграцию, но требует внимания к обработке ошибок — Boxberry иногда возвращает ошибки в теле 200-ответа вместо HTTP-статусов.

Базовая структура клиента

class BoxberryClient
{
    private string $baseUrl = 'https://api.boxberry.ru/json.php';

    public function request(string $method, array $params = []): array
    {
        $response = Http::get($this->baseUrl, array_merge([
            'token'  => config('services.boxberry.token'),
            'method' => $method,
        ], $params));

        $data = $response->json();

        // Boxberry возвращает ошибки как {"err":"текст ошибки"}
        if (isset($data['err'])) {
            throw new BoxberryApiException("Boxberry API error [{$method}]: {$data['err']}");
        }

        return $data;
    }
}

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

Метод DeliveryCosts считает стоимость по коду города или индексу ПВЗ:

public function calculateDelivery(
    string $targetCity, // код города Boxberry
    float  $weightKg,
    array  $dimensions, // ['length'=>20, 'width'=>15, 'height'=>10], см
    float  $declaredValue = 0,
    bool   $toPickupPoint = true
): array {
    $params = [
        'token'      => config('services.boxberry.token'),
        'method'     => $toPickupPoint ? 'DeliveryCosts' : 'DeliveryCostsD2D',
        'weight'     => (int)($weightKg * 1000), // граммы
        'target'     => $targetCity,
        'OrderSum'   => (int)$declaredValue,
        'height'     => $dimensions['height'],
        'width'      => $dimensions['width'],
        'depth'      => $dimensions['length'],
    ];

    $response = Http::get($this->baseUrl, $params)->json();

    if (isset($response['err'])) {
        throw new BoxberryApiException($response['err']);
    }

    return [
        'price'    => (float)$response['price'],
        'price_base' => (float)($response['price_base'] ?? $response['price']),
        'min_days' => (int)$response['delivery_period'],
    ];
}

Boxberry разделяет доставку до ПВЗ (DeliveryCosts) и курьерскую до двери (DeliveryCostsD2D). Второй метод доступен не везде — перед показом опции курьерской доставки стоит проверить доступность.

Список городов с ПВЗ

Справочник городов загружается один раз и кешируется:

public function getCitiesWithPoints(): array
{
    return Cache::remember('boxberry_cities', now()->addDay(), function () {
        return $this->request('ListCitiesShort');
        // Возвращает: [{"Code":"77","Name":"Москва","Prefix":"77"}, ...]
    });
}

Пункты выдачи

public function getPickupPoints(?string $cityCode = null, bool $prepaid = true): array
{
    $params = ['prepaid' => $prepaid ? 1 : 0];
    if ($cityCode) {
        $params['CityCode'] = $cityCode;
    }

    $points = $this->request('ListPoints', $params);

    return collect($points)->map(fn($p) => [
        'code'        => $p['Code'],
        'name'        => $p['Name'],
        'address'     => $p['Address'],
        'city'        => $p['CityName'],
        'lat'         => (float)$p['GPS']['Latitude'],
        'lng'         => (float)$p['GPS']['Longitude'],
        'work_time'   => $p['WorkShedule'],
        'phone'       => $p['Phone'] ?? null,
        'metro'       => $p['Metro'] ?? null,
        'cash_allowed'=> (bool)($p['HaveCash'] ?? false),
        'card_allowed'=> (bool)($p['HaveCardPayment'] ?? false),
        'fitting_room'=> (bool)($p['ForeignOnlineStore'] ?? false),
    ])->toArray();
}

Метод ListPoints без параметра города возвращает все ПВЗ России — это несколько мегабайт JSON. Лучше фильтровать по городу или загружать всё сразу и хранить локально.

Создание посылки

public function createParcel(Order $order): string
{
    $items = $order->items->map(fn($item) => [
        'id'     => (string)$item->product_id,
        'name'   => $item->product->name,
        'UnitName' => 'шт.',
        'nds'    => '20',
        'price'  => $item->price,
        'quantity'=> $item->quantity,
    ])->toArray();

    $payload = [
        'order_id'       => (string)$order->id,
        'barcode'        => '', // Boxberry присвоит сам
        'targetstart'    => $order->pickup_point_code,
        'price'          => $order->delivery_cost,
        'payment_sum'    => $order->is_prepaid ? 0 : $order->total, // наложенный платёж
        'delivery_sum'   => $order->delivery_cost,
        'vid'            => 1, // 1=ПВЗ, 2=курьер
        'kurdost'        => ['idx' => $order->zip, 'citi' => $order->city, 'address' => $order->address],
        'customer'       => [
            'fio'   => $order->recipient_name,
            'phone' => $order->recipient_phone,
            'email' => $order->recipient_email,
        ],
        'items'          => $items,
        'weights'        => [
            'weight' => (int)($order->total_weight_kg * 1000),
            'x'      => $order->package_length,
            'y'      => $order->package_width,
            'z'      => $order->package_height,
        ],
    ];

    $response = Http::withHeaders(['Content-Type' => 'application/json'])
        ->post('https://api.boxberry.ru/json.php?token=' . config('services.boxberry.token') . '&method=ParselCreate',
            $payload
        )->json();

    if (isset($response['err'])) {
        throw new BoxberryApiException('ParselCreate: ' . $response['err']);
    }

    return $response['track']; // трек-номер
}

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

public function trackParcel(string $trackNumber): array
{
    $response = $this->request('ListStatuses', ['ImId' => $trackNumber]);

    return collect($response)->map(fn($s) => [
        'date'    => $s['Date'],
        'name'    => $s['Name'],
        'comment' => $s['Comment'] ?? '',
        'city'    => $s['CityName'] ?? '',
    ])->toArray();
}

Создание акта приёма-передачи

Перед передачей посылок в Boxberry нужно сформировать акт:

public function createTransferAct(array $trackNumbers): array
{
    $response = Http::post(
        'https://api.boxberry.ru/json.php?token=' . config('services.boxberry.token') . '&method=ParselSend',
        ['ImIds' => $trackNumbers]
    )->json();

    // Возвращает {'label': 'номер акта', 'sticker': 'base64 PDF со стикерами'}
    return $response;
}

Получение этикеток

public function getLabel(string $trackNumber): string
{
    // Возвращает base64-encoded PDF
    $response = $this->request('ParselGetLabel', ['ImId' => $trackNumber]);
    return base64_decode($response['pdf']);
}

Особенности и ограничения

Boxberry работает только с российскими адресами. Максимальный вес посылки — 31 кг, максимальный размер стороны — 150 см. Наложенный платёж доступен не во всех городах.

При тестировании используется тот же URL, но тестовый токен (выдаётся менеджером). Реальные посылки не создаются — данные уходят в тестовую среду.

Сроки

Расчёт стоимости + список ПВЗ на карте + создание заказов — 4–6 рабочих дней. Тестирование с реальным тестовым токеном, проверка граничных случаев (нестандартный вес, недоступный город) — 1–2 дня.