QR и счета — это два прямых способа принять оплату через Kaspi Pay из вашего кода: POST /v2/qr создаёт Kaspi QR-код для сканирования на кассе или в приложении, а POST /v2/invoices отправляет push-счёт прямо на телефон плательщика по его номеру. Оба эндпоинта требуют API-ключ (X-API-Key), обязательный заголовок Idempotency-Key и возвращают operation_id, по которому вы затем опрашиваете статус оплаты. Это низкоуровневый путь для собственного POS или бэкенда — если вам нужна готовая страница оплаты, используйте платёжные ссылки.
Все суммы — целые тенге (₸), минимум 100. Для аккаунтов с несколькими подключёнными Kaspi-кошельками добавляйте заголовок X-Kaspi-Account: ; без него берётся аккаунт по умолчанию.
Как создать QR-код для оплаты
Отправьте POST /v2/qr с суммой в тенге и обязательным заголовком Idempotency-Key. В ответ придёт operation_id, сырой qr_token (для отрисовки собственного QR), deep_link (открывает приложение Kaspi на телефоне) и время истечения expires_at — обычно около 5 минут.
curl -X POST https://api.paybot.kz/v2/qr \
-H "X-API-Key: kp_live_00112233445566778899aabbccddeeff" \
-H "Idempotency-Key: 7c1e9b2a-4d5f-4a8c-9e10-2b3d6f8a0c11" \
-H "X-Kaspi-Account: acc_01H..." \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"comment": "Заказ #1234",
"items": [{"name": "Кофе", "price": 1500, "qty": 1}]
}'import requests, uuid
resp = requests.post(
"https://api.paybot.kz/v2/qr",
headers={
"X-API-Key": "kp_live_00112233445566778899aabbccddeeff",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"amount": 5000, "comment": "Заказ #1234"},
)
qr = resp.json()
print(qr["operation_id"], qr["deep_link"], qr["expires_at"])Пример ответа 200 OK:
{
"operation_id": "1450012345",
"qr_token": "3010100100AC0000QRTOKEN...",
"deep_link": "https://kaspi.kz/pay?qr=3010...",
"expires_at": "2026-07-16T10:05:00Z",
"status": "created"
}Поля тела запроса: amount (обязателен, целые тенге, минимум 100), comment (опционально, ≤255 символов, виден плательщику) и items — опциональная корзина [{name, price, qty}]. Отрисуйте qr_token в QR-код в своём интерфейсе или дайте покупателю deep_link на телефоне.
Как проверить статус QR-операции
GET /v2/qr/{op_id} синхронизирует статус с Kaspi и возвращает нормализованное состояние, сумму, ФИО плательщика и сырой статус Kaspi для отладки.
curl https://api.paybot.kz/v2/qr/1450012345 \
-H "X-API-Key: kp_live_00112233445566778899aabbccddeeff"{
"operation_id": "1450012345",
"status": "paid",
"amount": 5000,
"sender_name": "IVAN I.",
"transaction_id": "TX1234567890",
"paid_at": "2026-07-16T10:03:12Z",
"raw_kaspi_status": "Processed"
}Поле raw_kaspi_status (Wait, Processed, Cancelled, Expired, …) полезно для поддержки, когда нормализованного status недостаточно. Опрашивать статус в цикле нужно не всегда — надёжнее подписаться на вебхук payment.completed и не поллить вручную.
Как отправить счёт (push на телефон)
POST /v2/invoices отправляет push-уведомление со счётом прямо в приложение Kaspi на телефоне плательщика — покупателю не нужно ничего сканировать. Требуется номер телефона в формате 7XXXXXXXXX (10–15 символов) и обязательный Idempotency-Key.
curl -X POST https://api.paybot.kz/v2/invoices \
-H "X-API-Key: kp_live_00112233445566778899aabbccddeeff" \
-H "Idempotency-Key: 9a2f4b6c-1d3e-4f8a-8c20-5e7b9d1f0a22" \
-H "Content-Type: application/json" \
-d '{"phone": "7771234567", "amount": 5000, "comment": "Заказ #1234"}'import requests, uuid
resp = requests.post(
"https://api.paybot.kz/v2/invoices",
headers={
"X-API-Key": "kp_live_00112233445566778899aabbccddeeff",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"phone": "7771234567", "amount": 5000, "comment": "Заказ #1234"},
)
print(resp.json())Пример ответа:
{
"operation_id": "1450098765",
"status": "created",
"expires_at": "2026-07-17T10:00:00Z"
}Счёт живёт около 24 часов (expires_at) — гораздо дольше QR. Поля запроса: phone (обязателен), amount (обязателен, целые тенге, минимум 100), comment (≤255, виден в push-уведомлении).
Как узнать статус счёта
GET /v2/invoices/{op_id} возвращает статус счёта, сумму, телефон плательщика и время оплаты.
curl https://api.paybot.kz/v2/invoices/1450098765 \
-H "X-API-Key: kp_live_00112233445566778899aabbccddeeff"{
"operation_id": "1450098765",
"status": "paid",
"amount": 5000,
"phone": "7771234567",
"paid_at": "2026-07-16T10:07:45Z"
}Как отменить счёт
POST /v2/invoices/{op_id}/cancel отменяет ещё не оплаченный счёт. В отличие от v1, этот вызов тоже требует заголовок Idempotency-Key.
curl -X POST https://api.paybot.kz/v2/invoices/1450098765/cancel \
-H "X-API-Key: kp_live_00112233445566778899aabbccddeeff" \
-H "Idempotency-Key: e1c3a5b7-2d4f-4a6c-8e90-1b3d5f7a9c33"Какие бывают статусы платежа
Нормализованный status в ответах QR и счёта принимает единый набор значений.
| Статус | Значение |
|---|---|
created | Операция создана, ждём оплату. |
paid | Оплачено. |
expired | Истёк срок (QR ~5 минут, счёт ~24 часа). |
cancelled | Отменено. |
failed | Оплата не удалась. |
refunded | По операции сделан возврат. |
Как правильно опрашивать статус
Опрос статуса нужен, когда вы не используете вебхуки. Соблюдайте несколько правил, чтобы не упереться в лимит API (20 запросов в минуту на боевой ключ).
- •Опрашивайте
GET /v2/qr/{op_id}илиGET /v2/invoices/{op_id}с интервалом в несколько секунд, а не в тугом цикле. - •Останавливайте поллинг, как только
statusстал финальным (paid,expired,cancelled,failed). - •Для QR прекращайте опрос после
expires_at— обновлять QR имеет смысл только выдав новый. - •По возможности вообще замените поллинг на вебхук
payment.completed— это надёжнее и не тратит лимит.
Заголовок Idempotency-Key обязателен на всех мутирующих вызовах (POST /v2/qr, POST /v2/invoices, POST /v2/invoices/{op_id}/cancel); генерируйте один ключ на одно намерение пользователя — подробнее в разделе Идемпотентность.
FAQ
Чем QR отличается от счёта?
QR (POST /v2/qr) создаёт код, который плательщик сам сканирует камерой или в приложении Kaspi — подходит для кассы, витрины и оплаты «здесь и сейчас». Счёт (POST /v2/invoices) отправляет push-уведомление прямо на телефон по номеру, и покупателю ничего сканировать не нужно — это удобно для дистанционной продажи, когда вы знаете номер клиента. QR живёт ~5 минут, счёт — ~24 часа.
Как долго живёт QR?
Около 5 минут — точное время истечения приходит в поле expires_at (UTC), ориентируйтесь на него, а не на константу. Когда QR истёк, а оплата ещё нужна, создайте новый вызовом POST /v2/qr. Счёт, в отличие от QR, действует примерно сутки.
Как отличить тестовый платёж от боевого?
По префиксу API-ключа: kp_test_... работает в песочнице (sandbox), kp_live_... — в бою. В тестовом режиме обходятся rate-limit и проверка живости Kaspi-сессии, а операции не списывают реальные деньги. Подробнее — в разделе о тестировании.
Нужен ли `X-Kaspi-Account`, если кошелёк один?
Нет. Заголовок X-Kaspi-Account нужен только при нескольких подключённых Kaspi-аккаунтах, чтобы выбрать, на какой из них принять оплату. Если аккаунт один, PayBot возьмёт его по умолчанию.