1C-Bitrix Integration with Kazpost Delivery Service (Kazakhstan)
Kazpost is the national postal operator of Kazakhstan. Coverage spans all localities in the country, including hard-to-reach areas. For e-commerce targeting the Kazakhstani market, Kazpost is essential where private courier services do not operate. The API provides a REST interface with token-based authorization.
Kazpost API: Connection
Kazpost provides its API through the partner portal. Production base URL: https://api.kazpost.kz/api/v1/. Authorization via API key in the Authorization: Bearer TOKEN header.
private function apiRequest(string $method, string $path, array $data = []): array
{
$url = 'https://api.kazpost.kz/api/v1' . $path;
$ch = curl_init($method === 'GET' ? $url . '?' . http_build_query($data) : $url);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->getOption('API_TOKEN'),
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => $method !== 'GET' ? json_encode($data) : null,
]);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code >= 400) {
throw new \RuntimeException("Kazpost API error {$code}: {$response}");
}
return json_decode($response, true) ?? [];
}
Cost Calculation
public function calcPrice(
string $fromZip,
string $toZip,
int $weightGram,
string $mailType = 'SMALL_PACKAGE'
): float {
$response = $this->apiRequest('POST', '/tariff/calculate', [
'fromZip' => $fromZip,
'toZip' => $toZip,
'weight' => $weightGram,
'mailType' => $mailType, // SMALL_PACKAGE, PACKAGE, EMS
'addServices' => [],
]);
return (float)($response['totalCost'] ?? 0);
}
Shipment types: SMALL_PACKAGE (small packet, up to 2 kg), PACKAGE (parcel), EMS (express). Cost is calculated in Kazakhstani tenge.
Postal Code Lookup by Address
Calculation requires the recipient's postal code. Kazpost provides a postal code lookup API:
public function findZipByAddress(string $city, string $street, string $house): ?string
{
$cacheKey = 'kazpost_zip_' . md5($city . $street . $house);
$cached = \Bitrix\Main\Data\Cache::createInstance();
if ($cached->startDataCache(86400 * 7, $cacheKey, '/kazpost')) {
$response = $this->apiRequest('GET', '/address/search', [
'city' => $city,
'street' => $street,
'house' => $house,
]);
$zip = $response[0]['zip'] ?? null;
$cached->endDataCache(['zip' => $zip]);
}
return $cached->getVars()['zip'];
}
The "Postal Code" field on the website can be filled in automatically: the customer enters an address, an AJAX request determines the postal code. Cache for one week — postal codes rarely change.
Creating a Postal Item
public function createMailItem(\Bitrix\Sale\Shipment $shipment): string
{
$order = $shipment->getOrder();
$props = $order->getPropertyCollection();
$payload = [
'mailType' => 'PACKAGE',
'weight' => $this->getWeight($shipment),
'declaredValue' => (int)($order->getPrice() * 100), // in tiyn
'cashOnDelivery' => 0,
'sender' => [
'name' => $this->getOption('SENDER_NAME'),
'zip' => $this->getOption('SENDER_ZIP'),
'address' => $this->getOption('SENDER_ADDRESS'),
'phone' => $this->getOption('SENDER_PHONE'),
],
'recipient' => [
'name' => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
'zip' => $props->getItemByOrderPropertyCode('KAZPOST_ZIP')?->getValue(),
'address' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
],
'items' => $this->buildItems($order),
];
$response = $this->apiRequest('POST', '/mail-items', $payload);
$barcode = $response['barcode'] ?? '';
$props->getItemByOrderPropertyCode('KAZPOST_BARCODE')?->setValue($barcode);
$order->save();
return $barcode;
}
The declared value (declaredValue) is passed in tiyn (1 tenge = 100 tiyn). This is a common feature of Kazakhstani APIs — account for the conversion.
Tracking
public function track(string $barcode): array
{
$response = $this->apiRequest('GET', '/tracking/' . $barcode);
$events = $response['events'] ?? [];
$last = end($events);
return [
'status' => $last['statusName'] ?? '',
'date' => $last['eventDate'] ?? '',
'location' => $last['locationName'] ?? '',
];
}
Timelines
| Scope | Timeline |
|---|---|
| Cost calculation + postal code lookup | 2–3 days |
| + Shipment creation + tracking | +2 days |
| + Cash on delivery | +1 day |







