Boxberry delivery service integration
Boxberry is a delivery network with focus on pickup points: over 15,000 locations across Russia. API is straightforward: token in header or parameter, JSON response, no OAuth. This simplifies integration but requires attention to error handling — Boxberry sometimes returns errors in 200-response body instead of HTTP statuses.
Basic client structure
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();
if (isset($data['err'])) {
throw new BoxberryApiException("Boxberry API error [{$method}]: {$data['err']}");
}
return $data;
}
}
Shipping rate calculation
Method DeliveryCosts calculates cost by city code or pickup point ID:
public function calculateDelivery(
string $targetCity,
float $weightKg,
array $dimensions,
float $declaredValue = 0,
bool $toPickupPoint = true
): array {
$method = $toPickupPoint ? 'DeliveryCosts' : 'DeliveryCostsD2D';
$response = Http::get($this->baseUrl, [
'token' => config('services.boxberry.token'),
'method' => $method,
'weight' => (int)($weightKg * 1000),
'target' => $targetCity,
'OrderSum' => (int)$declaredValue,
'height' => $dimensions['height'],
'width' => $dimensions['width'],
'depth' => $dimensions['length'],
])->json();
if (isset($response['err'])) {
throw new BoxberryApiException($response['err']);
}
return [
'price' => (float)$response['price'],
'min_days' => (int)$response['delivery_period'],
];
}
Boxberry separates pickup point delivery and door-to-door courier. Second method available not everywhere.
Cities and pickup points
public function getCitiesWithPoints(): array
{
return Cache::remember('boxberry_cities', now()->addDay(), function () {
return $this->request('ListCitiesShort');
});
}
public function getPickupPoints(?string $cityCode = null): array
{
$points = $this->request('ListPoints', ['CityCode' => $cityCode]);
return collect($points)->map(fn($p) => [
'code' => $p['Code'],
'name' => $p['Name'],
'address' => $p['Address'],
'lat' => (float)$p['GPS']['Latitude'],
'lng' => (float)$p['GPS']['Longitude'],
'work_time' => $p['WorkShedule'],
'cash_allowed' => (bool)($p['HaveCash'] ?? false),
])->toArray();
}
Creating parcel
public function createParcel(Order $order): string
{
$payload = [
'order_id' => (string)$order->id,
'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=pickup, 2=courier
'kurdost' => ['idx' => $order->zip, 'citi' => $order->city],
'customer' => [
'fio' => $order->recipient_name,
'phone' => $order->recipient_phone,
'email' => $order->recipient_email,
],
'weights' => [
'weight' => (int)($order->total_weight_kg * 1000),
],
];
$response = Http::post('https://api.boxberry.ru/json.php?token=' . config('services.boxberry.token') . '&method=ParselCreate',
$payload
)->json();
if (isset($response['err'])) {
throw new BoxberryApiException($response['err']);
}
return $response['track'];
}
Tracking
public function trackParcel(string $trackNumber): array
{
$response = $this->request('ListStatuses', ['ImId' => $trackNumber]);
return collect($response)->map(fn($s) => [
'date' => $s['Date'],
'name' => $s['Name'],
])->toArray();
}
Limitations
Boxberry works only with Russian addresses. Max weight 31 kg, max side 150 cm. Cash on delivery not available everywhere.
For testing use sandbox token (provided by manager).
Timeline
Rate calculation + pickup points + order creation — 4–6 working days.







