Как связать свою CRM с Kaspi-оплатами?

Обновлено 26 августа 2026 · Решение проблем · Версия в Markdown
Содержание
  1. Как это работает у вас
  2. Минимальный контракт интеграции
  3. Пошаговый сетап
  4. Идемпотентность: главная страховка CRM
  5. Несколько CRM или отделов — несколько токенов
  6. Грабли этого бизнеса
  7. Рекурренты: абонементы из CRM
  8. Филиалы и кассиры
  9. Мониторинг: «касса слетела» и дашборд
  10. Частые вопросы

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

CRM: сделка перешла в «Выставить счёт»
        │
POST /invoices  { phone_number, amount, external_order_id_idempotency: deal_id }
        │  201, status: processing → счёт уходит покупателю push'ем в Kaspi
        │
Покупатель оплачивает (у него 24 часа)
        │
Вебхук invoice.status_changed { status: paid, external_order_id: ... }
        │
CRM: находит сделку по external_order_id → двигает карточку в «Оплачено»

Никакого «входа в Kaspi по номеру телефона» из кода — CRM ходит только в REST ApiPay с заголовком X-API-Key; сессию с Kaspi держит ApiPay.

Минимальный контракт интеграции

Весь Kaspi API для CRM сводится к трём вызовам:

# Вызов Направление Зачем
1 POST /invoices CRM → ApiPay Создать счёт: phone_number (формат 8XXXXXXXXXX), amount, description ≤60, external_order_id, external_order_id_idempotency
2 POST {ваш webhook}invoice.status_changed ApiPay → CRM Единственный триггер движения сделки: paid / cancelled / expired / error
3 GET /invoices/{id} CRM → ApiPay Сверка/восстановление: если вебхук потерялся или нужен ручной рефреш карточки

Этого достаточно для «карточка двигается по оплате». Возвраты (POST /invoices/{id}/refund — см. возвраты) и корзина cart_items (при Kaspi ОФД) добавляются потом, по мере надобности.

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

  1. Ключи: в кабинете apipay.kz создайте API-ключ и вебхук-секрет. Это разные вещи: ключ — для ваших запросов, секрет — для проверки подписи входящих вебхуков (разница).
  2. Песочница: прогоните весь цикл в тестовом режиме — там есть simulate-оплата. Переключение в рабочий режим обратимо и ключи не меняет: отдельного sandbox-ключа в ApiPay нет (детали).
  3. Создание счёта из CRM:
curl -X POST https://api.apipay.kz/api/v1/invoices \
  -H "X-API-Key: ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "8701XXXXXXX",
    "amount": 45000,
    "description": "Сделка #4812, консультация",
    "external_order_id": "deal-4812",
    "external_order_id_idempotency": "deal-4812"
  }'

Ответ — 201 со status: "processing": счёт создаётся асинхронно, Kaspi ещё не вызван. Не пересоздавайте счёт, пока он в processing: получатся два живых счёта, и покупатель может оплатить оба.

  1. Приём вебхука: эндпоинт в CRM, проверка подписи X-Webhook-Signature: sha256=<hex> — HMAC-SHA256 по сырому телу запроса (пошагово). Отвечайте 2xx быстро, обработку — в очередь.
  2. Движение сделки: по external_order_id из payload находите сделку; paid → «Оплачено», expired → «Просрочен, перевыставить», error → на разбор менеджеру.
  3. Обработчик должен быть идемпотентным: ApiPay повторяет доставку недоставленных вебхуков (до 11 попыток с нарастающим интервалом) — повторная доставка paid не должна двигать сделку дважды.

Идемпотентность: главная страховка CRM

CRM ретраят HTTP-запросы, поэтому один заказ может превратиться в несколько счетов. Защита:

  • external_order_id_idempotency уникален в пределах организации (до 191 символа). Повтор → 409 duplicate_idempotency_key с invoice_id и статусом уже существующего счёта — просто используйте его.
  • Исключение by design: если прежний счёт уже мёртв (expired, cancelled, error), повторный POST с тем же ключом создаст новый счёт — это штатное перевыставление, 409 не будет.
  • Лучший ключ — ID сделки/заказа в вашей CRM: deal-4812. Ключ на попытку запроса (deal-4812-retry2) — антипаттерн, он отключает защиту.

Несколько CRM или отделов — несколько токенов

Если счета от одного юрлица выставляют две системы (например, CRM продаж и учётная система — для 1С есть отдельная страница), не делите один ключ — создайте отдельный API-ключ на каждую. У каждого ключа свой вебхук; в payload вебхука поле source содержит имя ключа-создателя, так что «чей счёт» всегда видно. Оплата тарифа при этом одна — тариф считается по организации, а не по числу ключей.

Грабли этого бизнеса

  1. Спам-цикл ретраев. No-code/ИИ-CRM без идемпотентности умеют выставить сотни счетов за минуты. Аварийный kill-switch — удалить API-ключи в кабинете, затем чинить логику ретраев и включать external_order_id_idempotency.
  2. Двойное движение сделки. Вебхуки доставляются повторно при ретраях — дедупите по invoice.id + status на своей стороне.
  3. processing — технический статус создания. Штатно он длится секунды. Дольше — либо у организации включён «Режим накопления счетов», либо выставление не доехало до Kaspi, и тогда сервис сам финализирует счёт в error с вебхуком. Пока счёт в processing, не пересоздавайте его — получатся два живых счёта; смотрите last_kaspi_error_* в GET /invoices/{id}.
  4. Каталог и скидки. Счёт по номеру (POST /invoices) можно выставить одной суммой amount даже у организации с каталогом — cart_items нужны только тогда, когда позиции должны попасть в чек Kaspi. Остальные правила корзины и скидок — cart_items и 422.
  5. 401 после запуска прода. При переключении режима ключ не меняется, поэтому 401 — это почти всегда перегенерированный ключ (в кабинете или партнёрским эндпоинтом) либо ключ другой организации в конфиге CRM. Сверьте key_hint того ключа, что лежит в конфиге.

Рекурренты: абонементы из CRM

Если CRM ведёт абонементы (спортзал, подписка на сервис, рассрочка), не пишите свой крон — используйте подписки ApiPay. Подписка = авто-выставление счетов (не автосписание с карты — в Kaspi его нет): система сама создаёт счёт в срок, клиент подтверждает оплату push'ем, а по счёту идут обычные invoice-вебхуки. В external_subscriber_id кладите ID клиента в CRM.

Один нюанс именно для CRM: события subscription.* не пишутся в webhook-логи и не имеют ручного retry — дедупьте по (событие, subscription.id) и не теряйте. Параметры, полный жизненный цикл и цены — в статье Подписки ApiPay и на витрине Рекуррентные платежи Kaspi.

Филиалы и кассиры

Одна организация может иметь несколько касс/торговых точек. Кассу для счёта выбираете полем kaspi_connection_id в POST /invoices (по умолчанию — основная касса). Если активных касс больше одной, основная не назначена и параметр не передан — вернётся 422 connection_ambiguous: передайте явный kaspi_connection_id.

Управлять кассирами прямо из CRM можно через /connections* — но только если у ключа включён флаг can_manage_cashiers (включает владелец в кабинете; без флага — 403 cashier_management_disabled). Сама процедура подключения и переавторизации кассира — «Подключение кассира Kaspi». Разделение отчётности и счетов по точкам — Раздельная отчётность по точкам.

Мониторинг: «касса слетела» и дашборд

Фоновый мониторинг CRM строится на GET /account/health: поля connection.session_status (active / expired / error) и connection.needs_reauth — так CRM детектит «слетела Kaspi-сессия» (вебхука на это нет); при плохом статусе — алерт менеджеру и запуск переавторизации. Там же tariff (дни до конца) и invoicing.accumulating. Для дашборда — GET /invoices/stats (period today/week/month/year или start_date+end_date) → виджеты «оплачено за период», «конверсия» (conversion_rate), «в ожидании» (включает processing). GET /status — liveness без авторизации.

Важно: тайм-зоны. Счета, возвраты и подписки в ответах — UTC +00:00, но GET /tariff и GET /account/health отдают +05:00 (Asia/Almaty). Частый баг — не учесть эту разницу в дашборде.

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

У нас нет своего API — CRM только «умеет ходить наружу». Хватит?

Да: наружу нужен один POST (создать счёт), внутрь — один URL для вебхука. Если CRM не может принять вебхук, остаётся поллинг GET /invoices/{id} — или сборка связки без своего сервера через n8n; но вебхук надёжнее и «мгновеннее».

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

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

Скопируйте готовый промпт и вставьте своему ИИ-ассистенту — он настроит интеграцию за вас: получит доступы, создаст тестовый счёт в песочнице и подключит вебхуки. Техническую часть делает ИИ, а не вы.

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