Один документ — весь сценарий подключения приёма платежей Kaspi Pay. Для GPT, Claude, Cursor, Copilot и других ИИ-ассистентов.
openapi.json, docs.html) НЕ нужно.
Передай клиенту своими словами 3 факта:
Это не блокер для начала интеграции. Новые организации создаются в песочнице по умолчанию — там счета создаются и без подключённого кассира: деньги никуда не идут, всё имитируется. Можно прямо сейчас писать код, создавать тестовые счета и принимать вебхуки.
Кассир Kaspi обязателен только при переходе в рабочий режим (шаг 8):
без активной сессии кассира реальные счета будут падать с
kaspi_session_not_configured. До этого момента подключение кассира —
параллельная задача клиента, она не должна тормозить разработку.
Когда клиент будет готов идти в прод, ему нужно подключить Kaspi Business как «Кассира» — это делается один раз, двумя способами на выбор. Кратко суть (передай клиенту, чтобы запустил это параллельно):
Определи тип проекта клиента:
X-API-Key — это секрет. Он используется ТОЛЬКО на сервере.
Никогда не помещай ключ в код, который выполняется в браузере клиента (frontend) — его
увидят все посетители сайта.
Это делает человек в кабинете на apipay.kz. Нужно войти под ролью Владелец или Разработчик — у роли «Менеджер» доступа к ключам нет. Точный путь по меню:
https://ваш-сайт.kz/webhooks/apipay).Сохрани значения в переменные окружения сервера (никогда — в репозиторий):
APIPAY_API_KEY=...
APIPAY_WEBHOOK_SECRET=...
APIPAY_BASE_URL=https://bpapi.bazarbay.site/api/v1
| Параметр | Значение |
|---|---|
| Базовый адрес API | https://bpapi.bazarbay.site/api/v1 |
| Авторизация | заголовок X-API-Key: ваш_ключ (только на сервере) |
| Content-Type | application/json |
| Лимит запросов | 60 в минуту на ключ |
https://bpapi.bazarbay.site/api/v1 —
он не зависит от того, на каком сайте ты читаешь эту инструкцию. Не используй адрес
документации (например localhost или apipay.kz) как адрес API.
POST /invoices// выполняется на сервере
const res = await fetch('https://bpapi.bazarbay.site/api/v1/invoices', {
method: 'POST',
headers: {
'X-API-Key': process.env.APIPAY_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone_number: '87001234567', // обязательно. Формат строго 8XXXXXXXXXX (11 цифр)
amount: 15000, // обязательно. Сумма в тенге
description: 'Заказ №123', // необязательно, до 500 символов
external_order_id: 'order_123' // необязательно — ваш ID заказа для сверки
})
})
const invoice = await res.json()
// → { id, amount, status: 'processing', phone, created_at }
Клиент получит уведомление в приложении Kaspi и оплатит там. Сохрани invoice.id
рядом со своим заказом.
GET /invoices/{id}Жизненный цикл статуса: processing → pending →
paid (или cancelled / expired / error).
Массовая проверка нескольких счетов сразу — POST /invoices/status/check
с телом {"invoice_ids":[1,2,3]}.
Когда счёт оплачен, ApiPay сам отправляет POST на твой адрес вебхука.
Тело события:
{
"event": "invoice.status_changed",
"invoice": {
"id": 42,
"external_order_id": "order_123",
"amount": "15000.00",
"status": "paid",
"paid_at": "2026-05-19T14:35:00+06:00"
},
"source": "имя вашего ключа",
"timestamp": "2026-05-19T14:35:01+06:00"
}
Другие события: invoice.refunded, subscription.payment_succeeded,
subscription.payment_failed, subscription.grace_period_started,
subscription.expired, webhook.test.
Каждый вебхук содержит заголовок X-Webhook-Signature: sha256=<hex> —
это HMAC-SHA256 от сырого тела запроса с секретом вебхука.
const crypto = require('crypto')
// rawBody — НЕОБРАБОТАННОЕ тело запроса (Buffer/строка), НЕ результат JSON.parse.
// В Express: app.post('/webhooks/apipay', express.raw({ type: 'application/json' }), ...)
function verifyWebhook(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}
2xx сразу,
тяжёлую работу делай в фоне.
Если твой сервер не ответил 2xx за 5 секунд (плюс до 3 секунд на соединение),
ApiPay повторит доставку. Всего до 11 попыток (первая + 10 повторов) с
нарастающей задержкой: 10с, 30с, 1м, 1.5м, 2м, 5м, 10м, 15м, 30м, 1ч — около 2 часов.
5xx/429/таймаут → повтор; прочие 4xx → без повтора.
invoice.id.
Если сервера нет (шаг 2b) — вместо вебхука опрашивай статус:
периодически вызывай GET /invoices/{id}, пока не будет paid.
Опрос полезен и при наличии вебхука — как сверка, если все 11 попыток не прошли.
Тестируй в тестовом режиме (песочнице) — счета не уходят в реальный Kaspi, деньги не двигаются. Новая организация в песочнице по умолчанию.
webhook.test. Убедись, что твой обработчик его
принял и подпись сошлась.POST /invoices.
В песочнице оплату счёта имитируют из кабинета — попроси клиента это сделать; придёт
вебхук invoice.status_changed со статусом paid.localhost, ApiPay
до него не достучится — подними туннель (ngrok). Инструкция:
apipay.kz/local-testing.POST /invoicesHTTP / поле error | Причина | Что сделать |
|---|---|---|
422, ошибка в phone_number | Телефон не в формате 8XXXXXXXXXX | Ровно 8 и 10 цифр, без +7, пробелов и скобок |
| 401 | Неверный, отсутствующий или истёкший X-API-Key |
Проверь ключ и заголовок (шаг 3) |
400 organization_required | Организация не подключена | Вернись к шагу 2 — подключить кассира |
400 Organization not found or not verified |
Организация есть, но не верифицирована (рабочий режим) | Дождаться верификации организации; пока тестируй в песочнице |
400 kaspi_session_not_configured |
Сессия Kaspi не настроена (только рабочий режим — в песочнице эта ошибка не возникает) | Клиенту подключить кассира: кабинет → Настройки → «Авторизация Kaspi», либо поддержка WhatsApp. Подробно — шаг 2a и /connect-cashier |
503 kaspi_session_invalid |
Сессия Kaspi истекла или неисправна (только рабочий режим) | Переподключить кассу по SMS (см. ниже) |
422 connection_ambiguous | У организации несколько касс, основная не выбрана | Передать в запросе kaspi_connection_id нужной кассы |
400 sandbox_invoice_limit | Лимит тестовых счетов исчерпан | Очистить песочницу в кабинете |
| 429 | Больше 60 запросов в минуту | Подожди и повтори; смотри retry_after |
Полная таблица ошибок (QR-счета, возвраты) — в docs.html.
errorСоздание счёта асинхронное: POST /invoices возвращает 201 со
статусом processing, дальше счёт уходит в Kaspi в фоне. Если что-то пошло
не так на стороне Kaspi — это не ошибка HTTP, а статус
error у счёта. Проверяй через GET /invoices/{id}:
status — стал error;error_message — причина текстом от Kaspi. Частое: номер клиента не
зарегистрирован в Kaspi; Kaspi временно недоступен.Ошибки Kaspi приходят сырым текстом, фиксированных кодов у них нет. «Номер не в Kaspi» — попроси клиента дать номер с установленным приложением Kaspi. «Временно недоступен» — повтори создание счёта позже.
kaspi_session_invalid)Сессия кассира стабильна и обычно живёт месяцами — ежедневно или
по расписанию переподключать кассу не нужно. Прерваться она может
только при конкретных событиях: владелец вошёл в Kaspi с другого устройства или
Kaspi сам сбросил сессию. В этом случае API отдаёт 503 kaspi_session_invalid.
Ретраи запроса не помогут: владелец организации один раз переподключает кассу по SMS —
кабинет, Настройки → «Авторизация Kaspi», либо через поддержку. Инструкция:
/connect-cashier.
Открой в кабинете Настройки → «Лог уведомлений» — там видно каждую отправку вебхука: адрес, HTTP-код ответа твоего сервера, отправленное тело и полученный ответ. Это главный инструмент диагностики:
localhost → ApiPay до него не достучится, нужен туннель (шаг 6).Когда тесты в песочнице прошли:
kaspi_session_not_configured (см. шаг 7).
Инструкция: /connect-cashier. Дождись подтверждения, что
кассир подключён, и только после этого переключай режим.
Готово — интеграция приёма платежей завершена.
| Что | Значение |
|---|---|
| Базовый адрес API | https://bpapi.bazarbay.site/api/v1 |
| Авторизация | X-API-Key (заголовок, только на сервере) |
| Создать счёт | POST /invoices |
| Статус счёта | GET /invoices/{id}, POST /invoices/status/check |
| Отмена / возврат | POST /invoices/{id}/cancel, POST /invoices/{id}/refund |
| Подписки (рекуррент) | POST /subscriptions + /pause, /resume, /cancel |
| Подпись вебхука | X-Webhook-Signature: sha256=…, HMAC-SHA256 от сырого тела |
| Поддержка | WhatsApp +7 708 516 74 89 |
Полная документация (нужна редко — этого плейбука достаточно для типовой интеграции): docs.html · apipay-api-docs.md · openapi.json · llms.txt
CRM и платформам, которые подключают чужих мерчантов: см.
Partner API (другой механизм — X-Partner-Key).