ГлавнаяБлог › Интеграция в CRM

Интеграция Kaspi Pay в Bitrix24, Kommo и amoCRM

Готовые сценарии: выставить счёт из карточки сделки одним кликом, автоматически перевести сделку в «Успешно» по вебхуку оплаты, отправить клиенту ссылку на чек. С примерами кода для каждой CRM и общей логикой, которую можно адаптировать под Pipedrive, Salesforce или Zoho.

14 мая 2026 · 16 мин чтения · CRM-интеграции

Bitrix24 Kommo amoCRM Webhooks

Общая схема

Независимо от конкретной CRM, картинка одна:

  1. Менеджер открывает карточку сделки и нажимает кнопку «Выставить счёт».
  2. CRM (или ваш middleware) собирает корзину из товаров сделки и зовёт POST /v1/invoice/create в PayProverkaBot.
  3. В ответ приходит paymentId, который сохраняется в поле сделки.
  4. Клиент получает push в Kaspi.kz, открывает и оплачивает.
  5. PayProverkaBot шлёт вебхук payment.success на ваш URL.
  6. Обработчик находит сделку по paymentId, переводит её в статус «Успешно», прикладывает receiptUrl, ставит задачу на отгрузку.

Главный нюанс: первая часть (CRM → API) — синхронный HTTP, простой. Вторая часть (API → CRM) — асинхронный вебхук, требует идемпотентного приёмника с проверкой подписи.

Bitrix24

Шаг 1. Действие «Выставить счёт» в роботе

В Bitrix24 у сделок есть роботы и триггеры. Самый простой путь — настроить «Робот: исходящий вебхук» при перемещении сделки в стадию «Готов к оплате». Робот шлёт POST на ваш middleware, который и зовёт PayProverkaBot.

Зачем middleware между Bitrix24 и нами: чтобы спрятать X-API-Key и привести данные в нужный формат. Робот Bitrix24 не позволяет переименовать поля так, как требует наша схема.

# middleware.py — небольшой FastAPI-приёмник между Bitrix24 и PayProverkaBot
import os, requests
from fastapi import FastAPI, Request, HTTPException

app = FastAPI()
KASPI_KEY = os.environ["KASPI_API_KEY"]
BX_TOKEN  = os.environ["BX_INCOMING_TOKEN"]   # секрет, который Bitrix шлёт в POST

@app.post("/bitrix/issue-invoice")
async def issue_invoice(request: Request):
    payload = await request.json()
    if payload.get("auth", {}).get("application_token") != BX_TOKEN:
        raise HTTPException(401)

    deal_id  = payload["data"]["FIELDS"]["ID"]
    phone    = payload["data"]["FIELDS"]["PHONE"]
    products = payload["data"]["PRODUCTS"]  # [{NAME, PRICE, QUANTITY}, ...]

    items = [
        {"name": p["NAME"], "price": float(p["PRICE"]), "count": int(p["QUANTITY"])}
        for p in products
    ]

    r = requests.post(
        "https://pay.proverkacheka.kz/api/v1/invoice/create",
        headers={"X-API-Key": KASPI_KEY, "Content-Type": "application/json"},
        json={"phoneNumber": phone, "comment": f"Сделка #{deal_id}", "items": items},
        timeout=15,
    )
    r.raise_for_status()
    payment_id = r.json()["paymentId"]

    # Сохраняем paymentId в кастомное поле сделки UF_PAYMENT_ID
    bitrix_update_deal(deal_id, {"UF_PAYMENT_ID": payment_id})
    return {"ok": True, "payment_id": payment_id}

Шаг 2. Кастомное поле UF_PAYMENT_ID

В справочнике сделок добавьте пользовательское поле UF_PAYMENT_ID типа «Строка». Туда middleware пишет идентификатор счёта. По нему мы потом найдём сделку при приходе вебхука.

Шаг 3. Приём вебхука и перевод сделки

import hmac, hashlib

@app.post("/kaspi/webhook")
async def kaspi_webhook(request: Request):
    body = await request.body()
    sig  = request.headers.get("X-Webhook-Signature", "")
    expected = "sha256=" + hmac.new(
        os.environ["KASPI_WEBHOOK_SECRET"].encode(), body, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, sig):
        raise HTTPException(401)

    event = await request.json()
    if event["event"] != "payment.success":
        return {"ok": True}   # игнорируем остальные в этом коннекторе

    deal = bitrix_find_deal_by_field("UF_PAYMENT_ID", event["paymentId"])
    if not deal:
        return {"ok": True, "note": "no deal found"}

    bitrix_update_deal(deal["ID"], {
        "STAGE_ID":      "WON",
        "UF_RECEIPT_URL": event.get("receiptUrl") or "",
        "UF_PAID_AT":     event["timestamp"],
    })
    bitrix_create_task(
        deal["ASSIGNED_BY_ID"],
        title=f"Отгрузить заказ по сделке {deal['ID']}",
        deadline_hours=24,
    )
    return {"ok": True}
Карта полей в Bitrix24. Реальные имена полей зависят от вашей конфигурации. STAGE_ID для «Успешно» в Bitrix24 — обычно WON, но в кастомных воронках это C5:WON или схожий префикс. Проверьте через crm.dealcategory.stage.list.

Kommo (бывший amoCRM)

Шаг 1. Виджет или Salesbot

В Kommo два пути:

Для большинства команд достаточно Salesbot. Сценарий: «когда сделка перешла в этап «Готов к оплате», спросить менеджера ‘Выставить счёт?’, при ‘Да’ вызвать наш middleware».

# Тот же middleware из примера Bitrix24, но другой эндпоинт
@app.post("/kommo/issue-invoice")
async def kommo_issue(request: Request):
    payload = await request.json()
    # Salesbot шлёт {"lead_id": ..., "items": [...]} согласно вашему JSON-конструктору
    items = payload["items"]
    phone = payload["phone"]
    lead_id = payload["lead_id"]

    r = requests.post(
        "https://pay.proverkacheka.kz/api/v1/invoice/create",
        headers={"X-API-Key": KASPI_KEY, "Content-Type": "application/json"},
        json={"phoneNumber": phone, "comment": f"Сделка #{lead_id}", "items": items},
        timeout=15,
    )
    r.raise_for_status()
    payment_id = r.json()["paymentId"]

    # Записываем в кастомное поле сделки Kommo
    kommo_patch_lead(lead_id, custom_fields={"payment_id": payment_id})
    return {"ok": True, "payment_id": payment_id}

Шаг 2. Кастомное поле сделки

В Kommo: Настройки → Поля → Сделки → Добавить. Тип «Текст», название «Kaspi Payment ID». ID поля сохраните — оно нужно в API-вызовах (kommo_patch_lead).

Шаг 3. Вебхук

Логика идентична Bitrix24-варианту: получили payment.success, проверили подпись, нашли сделку по custom-полю, перевели в «Успешно», создали задачу. Меняется только клиент API (Kommo вместо Bitrix24).

Kommo считает «Успешно» статусом 142 (закрытое и реализованное) — этот ID одинаков у всех аккаунтов.

amoCRM

Технически amoCRM и Kommo — одна платформа (Kommo — это amoCRM, переименованный в Казахстане/СНГ после ребрендинга 2022 года). API одинаковый, шаги совпадают с предыдущим разделом. Единственное отличие — домен авторизации: your-account.amocrm.ru вместо your-account.kommo.com.

Если ваш бизнес работает с обеими версиями, средний слой можно держать общим: middleware принимает один и тот же формат полей, а наружу ходит по разным OAuth-токенам.

Что важно для всех трёх

Идемпотентность вебхука

PayProverkaBot может ретраить payment.success 2–10 раз (см. политику ретраев). Если обработчик каждый раз ставит новую задачу или меняет статус — менеджеры утонут в дублях. Минимальная защита:

def handle_event(event):
    key = f'{event["paymentId"]}:{event["event"]}'
    if redis.set(f"kaspi:processed:{key}", "1", nx=True, ex=86400 * 7) is None:
        # уже обрабатывали в последние 7 дней — выходим
        return
    # дальше — основная логика

Карта полей: счёт ↔ сделка

Минимально нужно три кастомных поля в каждой CRM:

Поле в CRMЧто хранитКогда заполняется
payment_idpaymentId из KaspiВ момент создания счёта
receipt_urlСсылка на фискальный чекПри payment.success
paid_atДата/время оплатыПри payment.success

Обратная связь клиенту

После успешной оплаты полезно отправить клиенту ссылку на чек receiptUrl — это снимает 80% «а где мой чек?» в поддержку. Все три CRM позволяют послать SMS / email-шаблон по триггеру.

Если же бизнес наоборот — принимает чеки от клиентов как доказательство оплаты на другой счёт — у нашей экосистемы есть парный сервис ProverkaCheka.kz, который валидирует фискальные чеки Kaspi через API. Те же команды, те же ИИН/БИН, но в обратную сторону.

Типичные ошибки

СимптомПричинаЧто делать
400 invalid_phone при создании счёта В CRM-сделке телефон записан как +7 (701) ... с лишними символами Сервис нормализует, но если в строке меньше 10 цифр — упадёт. Очищайте на стороне middleware: оставьте только цифры, проверьте длину.
412 kaspi_session_required Кто-то залогинился в Kaspi Pay на телефоне — сессия сервиса выгнана Откройте бот → /login и пройдите SMS. После этого вебхуки и API возобновятся.
Вебхук приходит, но сделка не находится paymentId не записался в CRM (например, middleware ответил 5xx) В middleware: сначала запись в CRM, потом возврат успешного ответа. Если запись упала — Kaspi-счёт уже создан, но «осиротевший».
Менеджер получает несколько одинаковых задач Нет защиты от ретраев вебхука Идемпотентность по (paymentId, event), см. выше.
Сделка переведена в «Успешно», но клиент потом запросил возврат Не подписаны на payment.refunded Подпишитесь и в обработчике переводите сделку обратно в специальный этап «Возврат».

Чек-лист продакшна