Как принимать оплату Kaspi интернет-магазину — без Kaspi-магазина?

Обновлено 6 июля 2026 · Решение проблем · Версия в Markdown
Содержание
  1. Почему магазины приходят к ApiPay
  2. Как это работает у вас
  3. Компоненты ApiPay для магазина
  4. Пошаговый сетап
  5. Грабли именно магазинов
  6. Мини-кейс: магазин на конструкторе сайтов
  7. Для разработчиков: собрать checkout
  8. Частые вопросы

Почему магазины приходят к ApiPay

Часто малому и среднему бизнесу нужен REST-приём Kaspi, а собственной интеграции ещё нет. ApiPay — независимый сервис поверх вашего Kaspi Pay: даёт REST API (счёт по номеру и вебхук) через штатную роль «Кассир», без отдельного Магазина на Kaspi.kz и без оборотных требований.

Разблокировка простая: если у магазина уже есть Kaspi Pay, счета можно выставлять через REST API ApiPay — для этого нужен только номер кассира, отдельный Магазин на Kaspi.kz не требуется.

Как это работает у вас

Итоговая схема:

Frontend (Tilda / ваш сайт) → Backend (API магазина) → ApiPay API → Backend магазина получает вебхук об успешной оплате → заказ переводится в «Оплачен».

По-человечески: покупатель вводит номер телефона при оформлении → получает счёт push'ем в своём Kaspi → оплатил → ApiPay шлёт вебхук → вы закрываете сделку. Деньги идут напрямую на ваш Kaspi-счёт, ApiPay к ним доступа не имеет; тариф — фиксированная подписка, не процент с оборота.

Компоненты ApiPay для магазина

Магазину доступен весь Kaspi API:

Компонент Зачем магазину
Счёт по номеру Основной сценарий: push покупателю, счёт живёт 24 часа
Ссылка на оплату из счёта Можно отправить покупателю в WhatsApp — работает те же 24 часа
Вебхук Автоматическое подтверждение заказа; поллинг статуса — запасной вариант
Песочница Отладка интеграции без реальных денег; переход в прод — тумблер «Рабочий режим»
Подписки (авто-выставление) Для повторяющихся заказов; см. грабли — это не автосписание
Кабинет apipay.kz Ручные счета и возвраты, пока интеграция в работе

Пошаговый сетап

Инструкция из 4 шагов, которую поддержка отправляет каждому магазину, — плюс два практических шага:

  1. Зарегистрируйтесь на apipay.kz (вход по WhatsApp-OTP).
  2. Отладьте своё решение по документации apipay.kz/docs в режиме «Песочница»: создание счёта из корзины, обработка вебхука. Если у вас нет разработчика — скиньте вашему ИИ ссылку apipay.kz/for-ai и документацию: он соберёт интеграцию под ваш сайт (это стандартная рекомендация поддержки, так подключаются магазины на Tilda и WordPress; удобно собирать в Lovable).
  3. Подключите номер кассира (отдельная SIM — требования).
  4. Включите «Рабочий режим» — у вас будет 3 дня на живые тесты (что меняется при переходе — внимание: тестовые ключи перегенерируются).
  5. Проверьте боевой сквозной сценарий: заказ → счёт → оплата → вебхук → статус заказа.
  6. Выберите тариф по дневному объёму счетов — фиксированная подписка, не процент; актуальные тарифы на apipay.kz.

Грабли именно магазинов

  • «Всё настроили, а оплаты не приходят» — причина №1 у новых магазинов: песочница не выключена. Счета в тестовом режиме в Kaspi не передаются; покупатель на ссылке видит «Пожалуйста, повторите позднее». Решается одной кнопкой «Включить рабочий режим».
  • Подписки ≠ автосписание. Магазины нередко ждут автосписаний, как в карточных эквайрингах. Оплата по номеру так не работает, и в этом суть модели: автосписания нет — счёт просто выставляется автоматически, а клиент получает push и сам нажимает «Оплатить». Если нужен свой график, это те же обычные счета, настроенные по крону на вашей стороне. Поняв это, часть магазинов отказывается от подписок и заметно упрощает интеграцию.
  • Плагина под Tilda/WordPress нет — и это осознанная позиция: REST-запросы по /docs собирает ваш ИИ за вечер. Не ждите «модуль из каталога».
  • Номер покупателя должен быть в Kaspi. Если покупатель ввёл номер с опечаткой, счёт может уйти чужому человеку или никому: валидируйте номер на форме и показывайте покупателю, куда ушёл счёт.
  • Переход в прод перегенерирует ключи. Тестовые организации и ключи удаляются при включении рабочего режима — перебейте ключ и вебхук-секрет в конфиге сайта.

Мини-кейс: магазин на конструкторе сайтов

Типичный путь магазина на конструкторе сайтов (например, Tilda), у которого ещё нет собственной интеграции с Kaspi, выглядит так. Сначала магазин регистрируется на apipay.kz и отлаживает решение по документации apipay.kz/docs в режиме «Песочница». Готового плагина под конструктор нет, поэтому интеграцию собирают REST-запросами — как правило, с помощью ИИ-помощника. Затем подключают номер кассира и включают «Рабочий режим», получив несколько дней на живые тесты. За пару-тройку дней интеграция обычно выходит на рабочий режим, а магазин подбирает подходящий тариф по объёму счетов.

Для разработчиков: собрать checkout

Ниже — практическая часть для backend/full-stack разработчика магазина. Хост API — https://api.apipay.kz/api/v1, заголовок X-API-Key (ключ держите только на сервере, никогда в браузере).

Способ оплаты: счёт по номеру или QR

Два способа, выбор — под ваш UX:

Счёт по номеру (POST /invoices) QR (POST /invoices/qr)
Как платит клиент Kaspi шлёт push на номер, клиент платит в приложении На странице показываем QR-картинку/ссылку, клиент сканирует
Нужен телефон да (phone_number) нет
Ответ 201 со status: "processing" 201 сразу status: "pending" + QR-поля
pending-вебхук да (processing → pending) нет (статус уже в синхронном ответе)
description до 500 символов до 100 (наименование позиции в QR-чеке)
Жизнь счёта 24 часа минуты (TTL ~5 минут)
Спец-лимит общий 200/min 60/min на организацию
Особое событие invoice.qr_scanned
Несколько QR сосуществуют: новый QR не гасит старый

Счёт по номеру — когда есть телефон клиента и ок «push в Kaspi» (доставка, менеджер оформляет). QR — оплата «здесь и сейчас» на экране. Ответ QR несёт qr_image_url (PNG 600×600), qr_token_url и qr_expires_at. Почему QR живёт минуты — в статье QR-счёт: TTL и лимиты.

Идемпотентный checkout

Повторный клик «Оплатить» или двойной сабмит не должны плодить счета. Защита — поле external_order_id_idempotency = ID заказа:

curl -X POST https://api.apipay.kz/api/v1/invoices \
  -H "X-API-Key: ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
  -d '{ "phone_number": "8XXXXXXXXXX", "amount": 5000,
        "description": "Заказ #1042",
        "external_order_id": "order-1042",
        "external_order_id_idempotency": "order-1042" }'

Повтор с тем же ключом → 409 duplicate_idempotency_key с телом { invoice_id, status }: покажите существующий счёт, не создавайте второй. external_order_id — метка для матчинга в вебхуке (по ней магазин находит заказ). Не проверяйте номер на каждый pageview через POST /clients/check — у него лимит 60/min + 10 000/день, массовый перебор ведёт к блокировке ключа; дёргайте точечно, перед созданием счёта.

Обработка вебхуков: статус → действие магазина

Статус в вебхуке Что произошло Действие магазина
pending Счёт создан в Kaspi (только счёт по номеру; для QR нет) Ждём оплату
paid Оплачен Пометить оплаченным, выдать/отгрузить. Может прийти после cancelled/expired — всё равно «деньги получены»
cancelled Отменён клиентом/магазином/кассиром Снять резерв, вернуть заказ в «ожидает оплаты»
expired Истёк (24ч по номеру / минуты по QR) Снять резерв, предложить оплатить заново
error (+ error_code) Терминальная техническая ошибка Показать «оплата не прошла», предложить заново (новый счёт)
partially_refunded Первый частичный возврат оформлен Отразить частичный возврат

Вебхук приходит как POST {ваш webhook} с заголовком X-Webhook-Signature: sha256=<hex>. Проверяйте подпись по сырому телу (raw body), не по перепарсенному JSON:

import crypto from 'crypto'
function verify(rawBody, header, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
  const got = Buffer.from(header || '')
  const exp = Buffer.from(expected)
  if (got.length !== exp.length) return false
  return crypto.timingSafeEqual(exp, got)
}
// secret = process.env.APIPAY_WEBHOOK_SECRET

Три правила обработчика: отвечать 200 быстро (до 5 с), обработку — в очередь; дедуп по (invoice.id, invoice.status) (повторы доставки возможны); реагировать на последний статус (cancelled → paid = деньги получены). Полный разбор доставки, ретраев и circuit breaker — в статье Вебхуки ApiPay: настройка и проверка подписи; здесь не дублируем. Если вебхук не пришёл (пауза breaker'а, сеть) — страховка через поллинг GET /invoices/{id}.

QR-UX: сканирование, ожидание, таймауты

Событие invoice.qr_scanned (в payload qr_substate: "scanned") означает, что клиент отсканировал QR и на экране оплаты; status при этом остаётся pending. Реакция UI: убрать QR, показать «Ожидается оплата». Важно: это транзиентно: возможен scanned → cancelled (клиент свернул приложение) — UI обязан откатить «Ожидается» и предложить новый QR. expired по QR приходит только когда Kaspi отдал терминал, а не по локальному таймеру. QR сосуществуют — реагируйте на paid/cancelled/expired по каждому invoice.id.

Возвраты при отмене заказа

POST /invoices/{id}/refund — полный (по умолчанию) или частичный (amount либо позиционный return_items[]). Результат приходит вебхуком invoice.refunded (completed/failed+error_code). Статуса refunded у счёта нет: полный возврат оставляет paid + is_fully_refunded=true. Причины отказов и окно возврата — Возвраты Kaspi через API.

Чек-лист: sandbox → прод

  • Прогнать весь жизненный цикл в песочнице: POST /invoices/{id}/simulate-status (paid/cancelled/expired/error/qr_scanned), проверить доставку через GET /webhook-logs?invoice_id=…; магические номера lookup — 87770000001 (есть Kaspi) / 87770000002 (нет).
  • Идемпотентность checkout (external_order_id_idempotency = ID заказа), дедуп и HMAC вебхуков.
  • Снятие резерва склада по expired/cancelled; обработка cancelled → paid как «деньги получены».
  • Уважать 429/Retry-After; даты в ответах — UTC (переводите в Asia/Almaty для витрины).
  • Что меняется при переходе — Песочница и рабочий режим: тестовые ключи и вебхук-секрет перевыпускаются, перебейте их в конфиге.

Частые вопросы

Нужен ли Kaspi-магазин или регистрация в Kaspi Merchant?

Нет. Нужны только Kaspi Pay вашего ИП/ТОО и отдельный номер под роль «Кассир».

Законно ли работать через ApiPay, если у нас нет собственной интеграции с Kaspi API?

ApiPay — независимый сервис, работающий через штатную роль «Кассир» в Kaspi Pay; деньги идут напрямую на ваш счёт. Мы не официальная интеграция Kaspi и не утверждаем обратного.

Сколько идёт подтверждение оплаты?

Обычно секунды; у неактивной организации — до ~10 минут. Стройте UX «подтверждение придёт на почту/WhatsApp», а не «ждите на странице».

Можно без бэкенда, прямо из Tilda?

Форме Tilda нужен обработчик, который вызовет API и примет вебхук, — это минимальный бэкенд (или low-code-связка). Ваш ИИ соберёт его по apipay.kz/for-ai.

Что с чеками ОФД?

Если у вас подключена Kaspi ОФД, счета создаются с корзиной (cart_items) и чек формируется по позициям каталога — см. статью про 422 и корзину.

Интеграция с ИИ

Не настраивайте вручную — поручите ИИ

Скопируйте готовый промпт и вставьте своему ИИ-ассистенту — он подключит приём платежей примерно за 15 минут. Настраивает ИИ, а не вы.

Остались вопросы — напишите нам в WhatsApp: +7 708 516 74 89. Отвечаем быстро, без звонков.

Написать в WhatsApp

Для разработчика. Полная спецификация API — apipay.kz/docs. Эта статья в Markdown — /guides/apipay-dlya-internet-magazina.md. Справочник фактов для ИИ-агента — apipay.kz/llms.txt.