Integration of 1C-Bitrix with the Europost delivery service (Belarus)

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

1C-Bitrix Integration with Evropochta Delivery Service (Belarus)

Evropochta is a Belarusian courier service operating through a pickup point (PUP) network. It covers major and mid-sized cities in Belarus well and is a popular alternative to Belpochta for e-commerce focused on delivery speed to pickup points. The API provides a JSON interface with key-pair authorization.

Connecting to the Evropochta API

Documentation and access keys are provided after signing a contract. Base URL: https://api.evropochta.by/api/. Authorization: token in the token header (not Authorization: Bearer — specifically a custom token header).

private function apiCall(string $method, string $endpoint, array $data = []): array
{
    $url = 'https://api.evropochta.by/api/' . ltrim($endpoint, '/');
    $ch = curl_init($method === 'GET' ? $url . '?' . http_build_query($data) : $url);

    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'token: ' . $this->getOption('API_TOKEN'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => $method === 'POST' ? json_encode($data) : null,
    ]);

    $result = json_decode(curl_exec($ch), true);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($code !== 200 || ($result['error'] ?? false)) {
        throw new \RuntimeException($result['error']['message'] ?? 'Evropochta API error');
    }

    return $result['data'] ?? $result;
}

Retrieving the Pickup Point List

public function getPickupPoints(?string $cityId = null): array
{
    $params = $cityId ? ['cityId' => $cityId] : [];

    $cacheKey = 'evropochta_pvz_' . ($cityId ?? 'all');
    $cached = \Bitrix\Main\Data\Cache::createInstance();

    if ($cached->startDataCache(3600 * 12, $cacheKey, '/evropochta')) {
        $points = $this->apiCall('GET', '/pickup-points', $params);
        $cached->endDataCache(['points' => $points]);
    }

    return $cached->getVars()['points'];
}

The pickup point list is cached for 12 hours — it does not change hourly. On the website it is displayed on a map (Yandex Maps or OpenStreetMap) or as a dropdown list with a city filter.

Cost Calculation

public function calcPrice(
    string $pvzCode,
    int $weightGram,
    float $declaredValue
): float {
    $response = $this->apiCall('POST', '/tariff', [
        'pvzCode'       => $pvzCode,
        'weight'        => $weightGram,
        'declaredValue' => $declaredValue,
    ]);

    return (float)($response['price'] ?? 0);
}

Cost is in Belarusian rubles. When integrating with 1C-Bitrix, verify the site's currency — if the store operates in multiple currencies, conversion via the National Bank of Belarus exchange rate is required.

Creating a Delivery Order

public function createOrder(\Bitrix\Sale\Shipment $shipment): string
{
    $order = $shipment->getOrder();
    $props = $order->getPropertyCollection();

    $payload = [
        'externalId'     => (string)$order->getId(),
        'pvzCode'        => $props->getItemByOrderPropertyCode('EVROPOCHTA_PVZ')?->getValue(),
        'recipientName'  => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
        'recipientPhone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
        'recipientEmail' => $props->getItemByOrderPropertyCode('EMAIL')?->getValue(),
        'weight'         => $this->getWeight($shipment),
        'declaredValue'  => $order->getPrice(),
        'codAmount'      => 0, // cash on delivery
        'items'          => $this->buildItems($order),
    ];

    $response = $this->apiCall('POST', '/orders', $payload);

    $trackNumber = $response['trackNumber'] ?? '';
    $props->getItemByOrderPropertyCode('EVROPOCHTA_TRACK')?->setValue($trackNumber);
    $order->save();

    return $trackNumber;
}

Tracking

public function getStatus(string $trackNumber): array
{
    $response = $this->apiCall('GET', '/tracking/' . $trackNumber);
    return [
        'status'   => $response['statusName'] ?? '',
        'date'     => $response['updatedAt'] ?? '',
        'pvzName'  => $response['pvzName'] ?? '',
    ];
}

Polling via agent every 2–3 hours for active shipments. Webhooks are not provided.

Status Mapping

Evropochta Status 1C-Bitrix Order Status
created Created
in_transit In transit
arrived Arrived at pickup point
delivered Issued to recipient
returned Returned
cancelled Cancelled

Timelines

Scope Timeline
Pickup point list + map + calculation 3–4 days
+ Order creation + tracking +2 days