Kommo + Checkout.com: платёжный gateway из воронки

Kommo + Checkout.com: платёжный gateway из воронки

При переходе сделки в статус «Выиграно» Kommo автоматически создаёт платёжную ссылку через Checkout.com API и сохраняет её в карточку. Менеджер отправляет ссылку клиенту одним кликом, а статус оплаты возвращается обратно в CRM через webhook - без ручных действий.

В проектах с EU e-commerce и fintech-компаниями на Kommo мы видим один и тот же паттерн: при выигрыше сделки менеджер вручную открывает Checkout.com dashboard, создаёт payment link, копирует его в карточку CRM, а потом ещё вручную отслеживает, прошла ли оплата. При объёме 50-80 сделок в месяц это 2-3 часа рутинной работы еженедельно, плюс постоянный риск ошибки - неверная сумма, не тот контакт, потерянная ссылка. Checkout.com занимает сильные позиции на EU-рынке именно потому, что поддерживает Strong Customer Authentication (SCA) по требованию PSD2 и имеет локальные acquiring-отношения в ключевых странах. Это делает его первым выбором для fintech и e-commerce компаний, которые работают с европейскими покупателями. В этой статье - архитектура интеграции, рабочий Python-код и реальный кейс с цифрами.

Почему нативной интеграции Checkout.com с Kommo нет

Kommo предлагает нативные подключения к Stripe и PayPal через маркетплейс виджетов, но Checkout.com там отсутствует. Причина не в технической сложности, а в рыночной логике: Checkout.com ориентирован на enterprise и mid-market клиентов с кастомными процессами, а не на low-code Zapier-интеграции.

Если пытаться решить задачу через Zapier или Make, вы сразу упираетесь в ограничения: нет готового Checkout.com-модуля с поддержкой Payment Links API v2, нет обработки HMAC-подписи webhook-событий, нет логики идемпотентности при повторных попытках. Всё это нужно строить вручную, и тогда проще сразу написать нормальный Python-сервис.

Payment Links API - это endpoint Checkout.com для генерации платёжных страниц без необходимости встраивать форму на сайт. Ссылка открывается на хостинге Checkout.com, поддерживает 3D Secure и возвращает webhook-события о результате оплаты.

Архитектура интеграции

Интеграция работает в двух направлениях:

  1. Kommo -> Checkout.com: при переходе сделки в статус «Выиграно» Kommo отправляет webhook на ваш сервис. Сервис получает данные сделки, создаёт Payment Link через Checkout.com API и записывает URL обратно в кастомное поле карточки.

  2. Checkout.com -> Kommo: когда покупатель оплачивает (или отказывается), Checkout.com отправляет webhook-событие на ваш сервис. Сервис обновляет статус сделки и добавляет заметку с деталями транзакции.

Технический стек:

  • Python 3.11 + FastAPI для webhook-обработчика
  • Checkout.com Secret Key для Bearer-авторизации
  • HMAC-SHA256 для верификации подписи входящих webhooks
  • Kommo API для обновления полей сделки

Поле reference в Payment Links API используется для хранения Kommo Deal ID - это связующее звено между платежом и сделкой в CRM.

import hmac
import hashlib
import httpx
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel

app = FastAPI()

CKO_SECRET_KEY = "sk_sbox_xxx"  # Checkout.com Secret Key
CKO_WEBHOOK_SECRET = "your_webhook_secret"  # из Checkout.com dashboard
KOMMO_SUBDOMAIN = "your_company"
KOMMO_TOKEN = "your_kommo_long_lived_token"


def verify_cko_signature(payload: bytes, signature_header: str) -> bool:
    """Верификация HMAC-SHA256 подписи от Checkout.com."""
    expected = hmac.new(
        CKO_WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)


async def create_payment_link(deal_id: int, amount: int, currency: str, contact_email: str) -> str:
    """Создаёт Payment Link в Checkout.com и возвращает URL."""
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.checkout.com/payment-links",
            headers={
                "Authorization": f"Bearer {CKO_SECRET_KEY}",
                "Content-Type": "application/json"
            },
            json={
                "amount": amount,         # в минимальных единицах (cents)
                "currency": currency,     # "EUR", "GBP", "USD"
                "reference": str(deal_id),  # Kommo Deal ID как reference
                "description": f"Invoice #{deal_id}",
                "customer": {"email": contact_email},
                "3ds": {"enabled": True},  # SCA для EU
                "expires_in": 86400        # 24 часа
            },
            timeout=10.0
        )
        response.raise_for_status()
        return response.json()["_links"]["redirect"]["href"]


async def update_kommo_deal(deal_id: int, payment_url: str, field_id: int):
    """Записывает Payment Link URL в кастомное поле сделки Kommo."""
    async with httpx.AsyncClient() as client:
        await client.patch(
            f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4/leads/{deal_id}",
            headers={"Authorization": f"Bearer {KOMMO_TOKEN}"},
            json={"custom_fields_values": [{"field_id": field_id, "values": [{"value": payment_url}]}]},
            timeout=10.0
        )


@app.post("/kommo/webhook")
async def handle_kommo_webhook(request: Request):
    """Обрабатывает webhook от Kommo при смене статуса сделки."""
    data = await request.json()
    # Проверяем что это событие выигрыша сделки
    leads = data.get("leads", {}).get("status", [])
    for lead in leads:
        if lead.get("status_id") == 142:  # ID статуса Won в вашей воронке
            deal_id = lead["id"]
            # Здесь получаем amount и email из полей сделки
            # (упрощено для примера)
            payment_url = await create_payment_link(
                deal_id=deal_id,
                amount=lead.get("price", 0) * 100,  # конвертируем в cents
                currency="EUR",
                contact_email=lead.get("contact_email", "")
            )
            await update_kommo_deal(deal_id, payment_url, field_id=12345)
    return {"status": "ok"}


@app.post("/checkout/webhook")
async def handle_checkout_webhook(request: Request):
    """Обрабатывает входящие webhook-события от Checkout.com."""
    body = await request.body()
    signature = request.headers.get("cko-signature", "")

    if not verify_cko_signature(body, signature):
        raise HTTPException(status_code=401, detail="Invalid signature")

    event = await request.json()
    event_type = event.get("type")
    deal_id = int(event["data"]["reference"])  # наш Kommo Deal ID

    if event_type == "payment_captured":
        # Оплата прошла - перемещаем сделку или добавляем заметку
        await update_kommo_deal_note(deal_id, f"Оплата получена: {event['data']['amount']} {event['data']['currency']}")
    elif event_type == "payment_declined":
        await update_kommo_deal_note(deal_id, f"Оплата отклонена: {event['data']['response_summary']}")

    return {"status": "ok"}

Пошаговая реализация

Шаг 1. Настройка Checkout.com

В Checkout.com Dashboard перейдите в Settings -> Channels. Скопируйте Secret Key (начинается с sk_). В разделе Webhooks создайте endpoint, укажите URL вашего сервиса и включите события: payment_captured, payment_declined, payment_approved. Сохраните Webhook Secret для HMAC-верификации.

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

В Kommo создайте кастомное поле типа «Текст» с названием «Payment Link» (запомните его field_id из API). Это поле будет хранить ссылку для отправки клиенту.

Шаг 3. Webhook из Kommo

В настройках Kommo (Настройки -> Уведомления) добавьте webhook на URL /kommo/webhook вашего сервиса. Настройте триггер на событие «Сделка: изменение этапа» для этапа «Выиграно».

Шаг 4. Маппинг полей сделки

Из webhook Kommo извлекайте price сделки (сумма контракта) и email контакта через API-запрос к /api/v4/leads/{id}?with=contacts. Валюту берите из кастомного поля или задайте по умолчанию.

Шаг 5. 3D Secure и SCA

Для EU-транзакций свыше 30 EUR включайте "3ds": {"enabled": true} в теле запроса к Payment Links API. Checkout.com автоматически применяет Strong Customer Authentication там, где это требует PSD2.

Шаг 6. Exponential backoff

Checkout.com API возвращает 429 при превышении rate limits. Реализуйте retry с задержками 1s, 2s, 4s, 8s (максимум 4 попытки) перед тем как зафиксировать ошибку и уведомить команду.

Реальный кейс: EU e-commerce, 65 сделок в месяц

Клиент - EU e-commerce компания, продаёт B2B через Kommo. До интеграции: менеджер вручную создавал payment link в Checkout.com после каждого звонка с подтверждением, копировал URL в карточку, писал письмо клиенту. Среднее время на операцию - 8-12 минут.

После интеграции: Payment Link создаётся автоматически при переходе в «Выиграно», URL появляется в карточке через 2-3 секунды. Менеджер видит ссылку, копирует в WhatsApp или email одним кликом. Статус оплаты (captured/declined) приходит в CRM автоматически.

Результат за первый месяц:

  • Экономия времени: ~7 часов в месяц (65 сделок x 6 минут)
  • Ошибки маппинга суммы: снизились с 4-5 в месяц до нуля
  • Конверсия из «Выиграно» в «Оплачено» выросла на 11% - за счёт скорости: ссылка уходит клиенту пока он ещё на звонке, а не через 30 минут

Дополнительный эффект: руководитель получил возможность отслеживать pipeline оплат прямо в Kommo без выгрузки из Checkout.com dashboard.

Для кого подходит эта интеграция

Эта схема оптимальна для компаний с несколькими характеристиками:

  • Используют Kommo как основной инструмент продаж
  • Принимают платежи от EU-покупателей (важна поддержка SCA)
  • Объём закрытых сделок от 30 в месяц - при меньшем объёме ручная работа не критична
  • Средний чек выше $500 - при небольших суммах административная нагрузка ощутимее
  • Нет выделенного billing-отдела, который берёт создание инвойсов на себя

Если вы уже используете Checkout.com и строите кастомные интеграции для Kommo, эта схема встраивается в существующий стек без замены инструментов.

Часто задаваемые вопросы

Можно ли использовать эту интеграцию, если мы принимаем оплату в нескольких валютах?

Да. Payment Links API принимает параметр currency при каждом создании ссылки. В Kommo создайте кастомное поле «Валюта сделки» и передавайте его значение в API-запрос. Checkout.com поддерживает более 150 валют. Курс конвертации на стороне Checkout.com при multicurrency acquiring, если вы используете эту функцию.

Что происходит, если webhook от Checkout.com приходит с задержкой или теряется?

Checkout.com повторяет доставку webhook до 10 раз с экспоненциальной задержкой в течение 24 часов. Дополнительно можно настроить polling через Events API - раз в 15-30 минут запрашивать события по reference (Deal ID) и сверять статусы. Для критичных транзакций рекомендуем комбинировать оба подхода.

Как верифицировать подпись webhook, если мы используем не Python?

Алгоритм одинаков для любого языка: берёте raw body запроса в байтах, считаете HMAC-SHA256 с вашим Webhook Secret, сравниваете с заголовком cko-signature. В Node.js это crypto.createHmac('sha256', secret).update(rawBody).digest('hex'). Важно: работать именно с raw body, а не с распарсенным JSON - иначе порядок полей может измениться.

По состоянию на середину 2026 года - да, если у вас настроен Apple Pay / Google Pay в вашем Checkout.com аккаунте. Покупатель, открывший Payment Link на мобильном, увидит доступные кошельки автоматически. Для этого не требуется дополнительная настройка на уровне API.

Нужен ли выделенный сервер для webhook-обработчика?

Нет. Достаточно VPS за $5-10/мес или бессерверной функции (AWS Lambda, Google Cloud Functions). Нагрузка минимальная: даже при 200 сделках в месяц это менее 20 запросов в день. FastAPI-сервис потребляет меньше 128MB RAM.


Если у вас 30+ закрытых сделок в месяц через Checkout.com и команда тратит время на ручное создание payment links - опишите задачу команде Exceltic.dev. Разберём архитектуру под ваш стек и оценим объём работ.

Ещё статьи

Все →