1C-Bitrix Integration with Kazpost Delivery Service
Situation: a client was losing up to 30% of orders due to non-functional delivery to Kazakhstan regions
An online store with a monthly turnover of 5 million tenge approached us. Private couriers delivered only to Almaty and Astana; to district centers, only Kazpost. The built-in Bitrix module failed: cost calculation returned errors, no tracking was available. Manual waybill creation took 2 hours per day, and index errors led to returns. We conducted an audit and decided to completely rewrite the delivery handler via the Kazpost REST API. Savings on manual order processing amounted to 15 hours per month. As a result, after implementation, the client automated 90% of orders, and processing time dropped from 30 minutes to 2 minutes per order. Additionally, we eliminated rounding errors that occurred due to incorrect currency conversion. Now buyers from any city in Kazakhstan can place delivery orders online, and the store receives up-to-date costs considering weight and declared value.
How the Kazpost Integration Works
Kazpost is the national postal operator with 3500+ branches. The API is available to partners after signing a contract. Base URL: https://api.kazpost.kz/api/v1. Authorization via X-Api-Key. Main methods:
-
POST /delivery/calculate— cost calculation -
POST /shipment/create— create a shipment -
GET /shipment/{barcode}/track— tracking -
GET /offices— list of offices by index
Learn more about REST API — the architecture the service is built on.
Cost Calculation
class KazposhtaHandler extends \Bitrix\Sale\Delivery\Services\Base
{
protected function calculateConcrete(
\Bitrix\Sale\Shipment $shipment
): \Bitrix\Sale\Delivery\CalculationResult {
$result = new \Bitrix\Sale\Delivery\CalculationResult();
$toIndex = $this->getPostIndex($shipment);
if (!$toIndex) {
$result->addError(new \Bitrix\Main\Error('Recipient postal index is missing'));
return $result;
}
$response = $this->apiPost('/delivery/calculate', [
'from_index' => $this->getOption('SENDER_INDEX'),
'to_index' => $toIndex,
'weight' => max((int)$shipment->getWeight(), 100),
'declared_value' => round($shipment->getOrder()->getPrice()),
'mail_type' => 'PARCEL',
'mail_class' => 'ORDINARY',
]);
if (!empty($response['total_rate'])) {
$result->setDeliveryPrice((float)$response['total_rate']);
$min = $response['delivery_days_min'] ?? 3;
$max = $response['delivery_days_max'] ?? 14;
$result->setPeriodDescription("{$min}–{$max} days");
}
return $result;
}
private function getPostIndex(\Bitrix\Sale\Shipment $shipment): ?string
{
$props = $shipment->getOrder()->getPropertyCollection();
$index = $props->getItemByOrderPropertyCode('ZIP')?->getValue();
return preg_match('/^\d{6}$/', (string)$index) ? $index : null;
}
}
The postal index is a required field. In the checkout form, we make it mandatory and validate the format (6 digits).
How to Set Up the Delivery Handler
- Install the Kazpost delivery module or create your own class extending
\Bitrix\Sale\Delivery\Services\Base. - Register the handler in the Bitrix admin panel: Settings → Delivery services → Add.
- Add order properties:
ZIP(index),ADDRESS,FIO,PHONE. For tracking — a custom propertyUF_KAZPOST_BARCODE. - Implement the
calculateConcreteandcreateShipmentmethods as shown above. - Set up an agent for periodic status polling.
Creating a Shipment
public function createShipment(\Bitrix\Sale\Shipment $shipment): string
{
$order = $shipment->getOrder();
$props = $order->getPropertyCollection();
$response = $this->apiPost('/shipment/create', [
'sender' => [
'index' => $this->getOption('SENDER_INDEX'),
'address' => $this->getOption('SENDER_ADDRESS'),
'name' => $this->getOption('SENDER_NAME'),
'phone' => $this->getOption('SENDER_PHONE'),
],
'recipient' => [
'index' => $props->getItemByOrderPropertyCode('ZIP')?->getValue(),
'address' => $props->getItemByOrderPropertyCode('ADDRESS')?->getValue(),
'name' => $props->getItemByOrderPropertyCode('FIO')?->getValue(),
'phone' => $props->getItemByOrderPropertyCode('PHONE')?->getValue(),
],
'parcel' => [
'weight' => max((int)$shipment->getWeight(), 100),
'declared_value' => round($order->getPrice()),
'mail_type' => 'PARCEL',
'description' => 'Goods',
],
'payment_type' => 'PREPAID',
]);
return $response['barcode'] ?? '';
}
We save the shipment barcode in UF_KAZPOST_BARCODE.
Why the Agent Is Mandatory for Tracking
The Kazpost API does not send webhooks — you must poll for statuses. We create a Bitrix agent running every 6 hours. It checks barcodes of orders in status "P" (paid) and when the status is "DELIVERED", it moves the order to "F" (delivered). It is important to set a timeout for API requests (we recommend 10–15 seconds) and log errors so that the agent does not hang if Kazpost fails. A retry mechanism for 500–503 errors helps avoid missing statuses.
function checkKazposhtaStatus(): string {
$orders = \Bitrix\Sale\Order::getList([
'filter' => ['=PROPERTY_VAL.UF_KAZPOST_BARCODE' => true, '=STATUS_ID' => 'P'],
'select' => ['ID']
]);
foreach ($orders as $order) {
$barcode = $order->getPropertyCollection()->getItemByOrderPropertyCode('UF_KAZPOST_BARCODE')->getValue();
$track = new KazposhtaHandler()->track($barcode);
if ($track['status'] === 'DELIVERED') {
$order->setField('STATUS_ID', 'F');
$order->save();
}
}
return 'checkKazposhtaStatus();';
}
When the API returns an error (e.g., 400 with body {"error": "Invalid index"}), the handler outputs the message: "The recipient's postal index is incorrect." All requests are logged in /bitrix/logs/kazpost.log for debugging.
Typical Integration Pitfalls
-
Invalid index format — must be 6 digits. Validate on the client side using an input mask and on the server via
preg_match('/^\d{6}$/'). On error, display "Please check the recipient's postal index." -
Missing required order properties (
ZIP,ADDRESS,FIO,PHONE) — prevent empty data with mandatory fields in the checkout form. Before making an API request, check withisset()and!empty(). -
Agent not configured for tracking — statuses will not update. Ensure the agent is registered in the admin panel and runs on schedule (cron). Check logs in
/bitrix/logs/if updates are missing. - Incorrect API key — returns 401. Verify the key is in environment variables and its expiration date with your Kazpost partner (keys require periodic contract renewal).
Kazpost Delivery Specifics
- Door-to-door delivery is available only in major cities (Almaty, Astana, Shymkent); elsewhere, delivery is to the post office.
- EMS is faster and more reliable for urgent shipments to large cities.
- Kazpost API supports cash on delivery (COD), with a commission of about 2% of the amount.
- Tariffs are calculated in tenge — check your store's currency settings.
Timeline and Stages
| Stage | Duration |
|---|---|
| Development of handler for calculation and shipment creation | 4–5 days |
| Connection of tracking and notifications | +2 days |
| Implementation of COD | +1 day |
| Testing on real orders | 1–2 days |
| Total | 7–10 days |
| Shipment Type | mail_type | mail_class | Description |
|---|---|---|---|
| Standard parcel | PARCEL | ORDINARY | Standard parcel |
| EMS | EMS | EMS | Expedited delivery |
| Valuable parcel | PARCEL | VALUABLE | With declared value |
What's Included in the Work
- Development of the delivery handler class (based on
\Bitrix\Sale\Delivery\Services\Base) - Configuration of order properties: index, address, barcode
- Creation of the tracking agent
- Integration with fiscalization (54-FZ) — discussed separately
- Testing on test and production environments
- Handover of documentation and access
Integration cost is calculated individually after analyzing your store. We guarantee stable operation. Our experience includes numerous successful integrations of 1C-Bitrix with postal services.
Get a consultation on integration — contact us. We will assess your project in 1 day and prepare a proposal. Request a calculation via email or our feedback form.







