1C-Bitrix Integration with Kaspi Pay Payment System (Kazakhstan)
Kaspi Pay is a payment instrument of the Kaspi Bank ecosystem. Widely distributed in Kazakhstan: the customer scans a QR code or enters a phone number, confirms payment in the Kaspi application. For online stores, it is relevant as one of the most conversion-effective payment methods in the Kazakhstani market.
Integration Options
Kaspi provides several methods for online stores:
QR Payment — a QR code with an invoice is generated. The customer scans it through the Kaspi.kz app. Used both on the website and at offline points.
Kaspi Pay by Link — a link leads to a confirmation form in the browser or opens the Kaspi application.
Kaspi eCommerce API — for online stores, direct API integration.
For Bitrix integration, the standard approach is eCommerce API or payment link.
Kaspi eCommerce API
Authorization via Bearer token. Base URL: https://api.kaspi.kz/payment/
$token = $this->getBusinessValue($payment, 'KASPI_TOKEN');
$orderId = $payment->getOrder()->getId();
$amount = $payment->getSum(); // in tenge (KZT)
// Create payment
$payload = [
'device' => [
'platformType' => 'WEB',
'id' => md5($orderId),
],
'amount' => [
'value' => $amount,
'currency' => 'KZT',
],
'externalId' => (string)$orderId,
'description' => 'Payment for order №' . $orderId,
'paymentType' => 'ECOM',
'customer' => [
'phone' => $phone, // customer phone in format +77XXXXXXXXX
],
'redirectUrl' => $returnUrl,
'callbackUrl' => $callbackUrl,
];
$ch = curl_init('https://api.kaspi.kz/payment/api/v1/payments/create');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
// $response['data']['paymentLink'] — redirect link
// $response['data']['paymentId'] — payment ID for status check
Handling Notifications
Kaspi sends a POST to callbackUrl when the payment status changes:
$rawBody = file_get_contents('php://input');
$data = json_decode($rawBody, true);
$paymentId = $data['data']['paymentId'];
$externalId = $data['data']['externalId']; // our orderId
$status = $data['data']['status']; // 'COMPLETED', 'FAILED', 'EXPIRED'
// Verification via signature header or additional status request
if ($status === 'COMPLETED') {
// Verify via separate GET request to protect against fake notifications
$verification = $this->httpGet(
'https://api.kaspi.kz/payment/api/v1/payments/' . $paymentId,
[],
['Authorization: Bearer ' . $token]
);
if ($verification['data']['status'] === 'COMPLETED') {
$order = \Bitrix\Sale\Order::loadByAccountNumber($externalId);
// setPaid('Y'), save()
}
}
http_response_code(200);
echo json_encode(['status' => 'OK']);
Important: always verify the status via an additional GET request to the API. Accepting the status from the callback body without verification is a fraud risk.
QR Code on Order Page
An alternative UX for mobile users — QR code directly on the checkout page:
// Get QR code for payment
$qrResponse = $this->httpPost('https://api.kaspi.kz/payment/api/v1/payments/qr', $payload, $headers);
$qrBase64 = $qrResponse['data']['qrCode']; // base64 PNG image
echo '<img src="data:image/png;base64,' . $qrBase64 . '" alt="Kaspi Pay QR">';
echo '<p>Scan QR in the Kaspi app</p>';
Additionally — implement polling or WebSocket for automatic status updates on the page without reloading.
Kazakhstani Market Characteristics
- Currency — tenge (KZT). Amounts without kopecks (whole numbers)
- Phone numbers in format
+77XXXXXXXXX(7 or 8 at the start — clarify the format with Kaspi) - Kaspi Pay is popular for payments from 5,000 to 500,000 KZT — main audience
- Kaspi also provides installment plans (Kaspi Red) — separate integration
Development Timeline
| Task | Timeline |
|---|---|
| Payment creation + redirect + callback | 2–3 days |
| QR code on page + polling status | +1–2 days |
| Testing on test environment | 0.5–1 day |







