Kommo + Mollie: платёжные ссылки и подписки из воронки продаж
Mollie — европейский платёжный шлюз с поддержкой iDEAL, SEPA Direct Debit, Bancontact, Klarna и всех основных карточных сетей. В отличие от Stripe, Mollie изначально ориентирован на EU-рынок и не требует отдельной настройки для каждого европейского метода оплаты. Без интеграции с Kommo менеджер после Won вручную открывает Mollie, создаёт платёж и отправляет ссылку клиенту. С интеграцией Won автоматически генерирует payment link с нужной суммой и методами оплаты, а событие payment.paid мгновенно переводит сделку на следующий этап.
Почему Mollie для EU-команд
Mollie поддерживает 25+ методов оплаты — большинство из них без дополнительных заявок:
— iDEAL (Нидерланды, 60%+ онлайн-платежей в стране)
— SEPA Direct Debit (для B2B-подписок в еврозоне)
— Bancontact (Бельгия), Sofort (Германия/Австрия), Przelewy24 (Польша)
— Klarna (рассрочка), Apple Pay, Google Pay
Для команды с клиентами в разных EU-странах Mollie означает один API вместо отдельных интеграций с локальными шлюзами. В сравнении с платёжными ссылками через Stripe — Mollie выигрывает по охвату европейских методов без дополнительных форм одобрения.
Что синхронизируется
Kommo -> Mollie:
— Won -> создать Mollie Payment Link с суммой из сделки
— Won -> создать Mollie Customer + Subscription (для recurring)
— Смена суммы сделки -> обновить черновик платежа
Mollie -> Kommo:
— payment.paid -> Note: «Mollie: платёж получен» + смена этапа
— payment.failed -> Note + задача менеджеру: «Платёж не прошёл»
— payment.expired -> Note: «Ссылка истекла без оплаты»
— subscription.charged_back -> Note + задача: «Чарджбэк — проверить»
Архитектура
Kommo Webhook: сделка перешла в Won
↓ Backend
1. GET /api/v4/leads/{id} + contacts
-> email, имя, сумма, описание
2. Mollie API: POST /v2/payments
-> amount, description, redirectUrl, webhookUrl
-> method: ["ideal","creditcard","sepadirectdebit"] или null (выбор клиента)
3. Kommo: PATCH /leads/{id}
-> кастомное поле mollie_payment_id = payment.id
-> кастомное поле mollie_checkout_url = payment._links.checkout.href
4. Kommo: POST /leads/{id}/notes
-> «Mollie: ссылка для оплаты отправлена»
5. (опционально) Отправить checkout URL клиенту через WhatsApp/email
Mollie Webhook: payment.paid
↓ Backend
1. GET /v2/payments/{id} -> верификация статуса
2. Найти сделку по mollie_payment_id
3. Kommo: PATCH /leads/{id} -> смена этапа «Оплата получена»
4. Kommo: POST /leads/{id}/notes -> «Mollie: оплата подтверждена, метод: {method}»
Mollie API: ключевые запросы
Base URL: https://api.mollie.com/v2.
Аутентификация: Bearer token — Authorization: Bearer {api_key}.
Тестовые ключи начинаются на test_, production — на live_.
Создать платёж:
import requests
MOLLIE_API_KEY = "live_your_api_key"
MOLLIE_BASE_URL = "https://api.mollie.com/v2"
headers = {
"Authorization": f"Bearer {MOLLIE_API_KEY}",
"Content-Type": "application/json"
}
def create_payment(amount_eur: float, description: str,
redirect_url: str, webhook_url: str,
customer_email: str = None) -> dict:
payload = {
"amount": {
"currency": "EUR",
"value": f"{amount_eur:.2f}" # Mollie требует строку "99.00"
},
"description": description,
"redirectUrl": redirect_url,
"webhookUrl": webhook_url,
"locale": "nl_NL", # или "en_US", "de_DE" и т.д.
}
if customer_email:
payload["metadata"] = {"customer_email": customer_email}
resp = requests.post(f"{MOLLIE_BASE_URL}/payments", headers=headers, json=payload)
resp.raise_for_status()
return resp.json()
def on_deal_won(lead: dict, contact: dict):
amount = lead.get("price", 0) / 100 # Kommo хранит в копейках/центах
email = get_contact_email(contact)
deal_id = lead["id"]
payment = create_payment(
amount_eur=float(amount),
description=f"Оплата сделки #{deal_id} - {lead.get('name', '')}",
redirect_url=f"https://yoursite.com/payment/success?deal={deal_id}",
webhook_url=f"https://your-backend.com/webhooks/mollie",
customer_email=email
)
checkout_url = payment["_links"]["checkout"]["href"]
payment_id = payment["id"]
update_kommo_deal(deal_id, {
"mollie_payment_id": payment_id,
"mollie_checkout_url": checkout_url
})
create_kommo_note(deal_id, f"Mollie: ссылка для оплаты создана\n{checkout_url}")
Обработка Mollie Webhook:
Mollie не подписывает webhook HMAC — вместо этого всегда делайте GET /v2/payments/{id} для проверки статуса. Не доверяйте status из тела webhook.
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhooks/mollie", methods=["POST"])
def mollie_webhook():
payment_id = request.form.get("id") # Mollie присылает form-encoded, не JSON
if not payment_id:
return "", 200
# Верификация: всегда запрашиваем статус через API
resp = requests.get(
f"{MOLLIE_BASE_URL}/payments/{payment_id}",
headers=headers
)
if not resp.ok:
return "", 200
payment = resp.json()
status = payment.get("status")
method = payment.get("method", "unknown")
deal_id = find_deal_by_field("mollie_payment_id", payment_id)
if not deal_id:
return "", 200
if status == "paid":
update_kommo_deal(deal_id, {"stage_id": STAGE_PAYMENT_RECEIVED})
create_kommo_note(deal_id,
f"Mollie: платёж получен (метод: {method}, статус: paid)")
elif status == "failed":
create_kommo_note(deal_id, "Mollie: платёж не прошёл")
create_kommo_task(deal_id, "Уточнить способ оплаты - Mollie зафиксировал ошибку")
elif status == "expired":
create_kommo_note(deal_id, "Mollie: ссылка для оплаты истекла без оплаты")
create_kommo_task(deal_id, "Отправить новую ссылку - предыдущая истекла")
return "", 200
Подписки (для recurring-платежей):
def create_mollie_subscription(customer_id: str, amount_eur: float,
interval: str = "1 month") -> dict:
resp = requests.post(
f"{MOLLIE_BASE_URL}/customers/{customer_id}/subscriptions",
headers=headers,
json={
"amount": {"currency": "EUR", "value": f"{amount_eur:.2f}"},
"interval": interval, # "1 month", "1 week", "1 year"
"description": "Ежемесячная подписка",
"webhookUrl": "https://your-backend.com/webhooks/mollie",
}
)
resp.raise_for_status()
return resp.json()
Важно: Mollie webhook присылает данные как application/x-www-form-urlencoded, а не JSON. Используйте request.form.get("id"), а не request.json.
Европейские методы оплаты: что указывать в method
Если передать "method": null — Mollie покажет клиенту все доступные методы для его страны. Для конкретного рынка:
# Нидерланды - iDEAL
payload["method"] = "ideal"
# Германия - приоритет SEPA + карты
payload["method"] = ["sepadirectdebit", "creditcard"]
# Бельгия
payload["method"] = ["bancontact", "creditcard"]
# Международный B2B
payload["method"] = ["creditcard", "sepadirectdebit", "paypal"]
Реальный кейс
SaaS (Нидерланды, B2B, Kommo + Mollie, 30–40 новых клиентов в месяц):
- До: менеджер после Won вручную создавал платёж в Mollie и отправлял ссылку в email. Задержка 1–4 часа. Клиенты из Нидерландов хотели iDEAL, из Германии — SEPA, из Бельгии — Bancontact. Три разных сценария — три ручных шага.
- После: Won -> ссылка с мультиметодом за 5 секунд. Клиент видит свой предпочтительный метод автоматически по геолокации.
payment.paid-> Note + смена этапа без вмешательства менеджера. - Дополнительно: истечение ссылки через 48 часов без оплаты -> автозадача менеджеру -> повторная отправка. Конверсия незакрытых платежей выросла на 22%.
Для кого актуально
- EU-компании с клиентами в Нидерландах, Германии, Бельгии, Польше — там Mollie покрывает локальные методы лучше Stripe
- SaaS с recurring subscription через SEPA Direct Debit
- B2B с крупными счетами — Mollie поддерживает платежи до €100k без отдельного одобрения
- Команды без Merchant of Record — в отличие от Paddle, Mollie не берёт на себя налоговую ответственность
Часто задаваемые вопросы
Mollie webhook — нужно ли верифицировать подпись?
Нет — у Mollie нет HMAC-подписи webhook. Вместо этого обязательно делайте GET /v2/payments/{id} для проверки реального статуса. Не обрабатывайте платёж только на основе данных из webhook-тела — это уязвимость.
Mollie поддерживает тестовые платежи без реальных денег?
Да. Тестовые API-ключи (test_...) позволяют создавать платежи с симуляцией всех статусов: paid, failed, expired, cancelled. В Mollie Dashboard -> Test mode — полная среда для разработки.
Чем Mollie отличается от Stripe для EU?
Mollie зарегистрирован и регулируется в Нидерландах (DNB), не требует отдельного одобрения для iDEAL/Bancontact/SEPA. Stripe поддерживает те же методы, но некоторые (SEPA Direct Debit) требуют подачи заявки. Для NL/BE-рынка Mollie — меньше бюрократии. Для глобального рынка и Stripe Connect — Stripe.
Как передать данные клиента в Mollie для SEPA?
Для SEPA Direct Debit сначала создайте Mollie Customer (POST /customers с name и email), затем используйте customerId при создании платежа. Клиент пройдёт mandating flow один раз, дальнейшие списания — без его участия.
Итого
- Mollie API: Bearer token,
https://api.mollie.com/v2 - Создать платёж:
POST /payments—amount.valueдолжен быть строкой"99.00" - Webhook: приходит
application/x-www-form-urlencodedсid— всегда верифицировать черезGET /payments/{id} - Нет HMAC-подписи — верификация через API-запрос, не через заголовок
- Хранить
mollie_payment_idв кастомном поле Kommo для обратного поиска - Метод
null= клиент выбирает сам из доступных в его стране
Если вы работаете с EU-клиентами и хотите автоматизировать выставление счетов через Mollie из воронки Kommo — опишите используемые методы оплаты. Exceltic.dev настроит маппинг и webhook-обработчик.