Если ваш клиент находится в Германии, Нидерландах или Скандинавии и говорит «нам нужна оплата частями» - это не каприз, это стандарт рынка. Klarna занимает доминирующую позицию в европейском B2B BNPL-сегменте, и команды продаж, которые работают на этих рынках, регулярно сталкиваются с запросом на гибкие условия оплаты. Проблема в том, что Kommo не умеет создавать Klarna-сессии нативно - менеджер копирует ссылку вручную или открывает отдельный кабинет Klarna, теряя контекст и время. В этой статье разбираем, как закрыть этот пробел через прямую интеграцию с Klarna Merchant API.
Почему это важно прямо сейчас
По данным Klarna Business Report 2024, более 85 миллионов активных пользователей в Европе регулярно используют BNPL-продукты Klarna при B2B-покупках. В DACH-регионе и Скандинавии «оплата позже» или «оплата частями» - не дополнительная опция, а ожидаемый способ расчётов при чеке выше 2 000 EUR. Команды продаж, которые не умеют быстро выставить Klarna-ссылку, просто теряют сделки в пользу конкурентов с более гибким процессом.
Операционная боль: что происходит без интеграции
Представьте типичный сценарий: менеджер по продажам ведёт сделку в Kommo на этапе «Отправить предложение». Клиент соглашается, но просит оплату частями через Klarna. Менеджер:
- Открывает Klarna Merchant Portal в отдельной вкладке
- Вручную вводит данные клиента и сумму
- Копирует ссылку и вставляет в переписку
- Возвращается в Kommo и добавляет заметку
- Через три дня проверяет статус оплаты снова вручную в Klarna Portal
Каждый из этих шагов - точка потери контекста. Нет единого места, где видно, кому отправлена ссылка, оплачено или нет, на какую сумму. Руководитель не может посмотреть в Kommo и понять, сколько сделок сейчас «ждут оплаты» через Klarna.
Почему нативного решения нет
Klarna не входит в стандартный маркетплейс интеграций Kommo. Это не удивительно: Klarna - платёжная инфраструктура с собственным процессом онбординга мерчантов, KYC-проверками и region-специфичными условиями. Zapier-коннекторы для Klarna существуют, но они работают только с уведомлениями и не умеют создавать payment session - для этого нужен вызов Klarna Merchant API напрямую.
Аналогичная ситуация была с Adyen и Mollie - подробнее о подходе к платёжным интеграциям в Kommo можно почитать в статьях Kommo + Adyen и Kommo + Mollie. Для более простого случая с разовыми платёжными ссылками через Stripe - смотрите отдельный гайд.
Что реализовали: архитектура
Полная схема работает следующим образом:
- Сделка в Kommo переходит на этап «Ожидание оплаты»
- Webhook от Kommo попадает на наш промежуточный сервис
- Сервис вызывает Klarna Merchant API и создаёт payment session
- URL сессии записывается в кастомное поле сделки в Kommo
- Менеджер видит ссылку прямо в карточке и отправляет клиенту
- Klarna присылает webhook при подтверждении авторизации
- Статус сделки обновляется автоматически, добавляется заметка
Промежуточный сервис - простой Python-микросервис (Flask или FastAPI), развёрнутый на вашей инфраструктуре или Railway.
Аутентификация Klarna API: Basic auth с Base64-кодированием
Klarna Merchant API использует HTTP Basic Authentication. Учётные данные - это пара из username (ваш API username, связанный с Merchant ID) и password (API secret). Они кодируются в Base64 и передаются в заголовке Authorization.
Важный момент: API credentials для playground-среды не работают в production и наоборот. Для тестирования используйте https://api.playground.klarna.com/, для боевой среды в Европе - https://api.klarna.com/.
import base64
import requests
KLARNA_API_USERNAME = "K123456_abc123def456" # ваш API username
KLARNA_API_PASSWORD = "your-api-secret" # ваш API secret
KLARNA_BASE_URL = "https://api.klarna.com" # production EU
# KLARNA_BASE_URL = "https://api.playground.klarna.com" # sandbox
def get_klarna_auth_header():
credentials = f"{KLARNA_API_USERNAME}:{KLARNA_API_PASSWORD}"
encoded = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
return {"Authorization": f"Basic {encoded}"}
Создание payment session при переходе сделки на этап
Kommo отправляет webhook при смене статуса сделки. Нам нужен обработчик, который при получении нужного status_id создаёт Klarna payment session.
Klarna endpoint: POST /payments/v1/sessions
Обязательные поля в теле запроса:
purchase_country- страна клиента (например,DEдля Германии)purchase_currency- валюта (например,EUR)locale- язык виджета Klarna (de-DE,nl-NL,sv-SEи т.д.)order_amount- сумма в центах (2500 EUR = 250000)order_lines- массив позиций заказаintent-buyдля разовой оплаты
В поле merchant_reference1 или merchant_data передаём ID сделки из Kommo - это понадобится при обработке webhook от Klarna.
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
KOMMO_SUBDOMAIN = "your-company" # ваш поддомен Kommo
KOMMO_ACCESS_TOKEN = "your-kommo-token"
KOMMO_STAGE_ID_AWAITING_PAYMENT = 12345678 # ID этапа "Ожидание оплаты"
KOMMO_CUSTOM_FIELD_KLARNA_URL = 98765432 # ID кастомного поля в Kommo
def create_klarna_session(lead_id, amount_cents, currency, country, locale, order_lines):
"""Создаёт Klarna payment session и возвращает session_id и client_token."""
headers = get_klarna_auth_header()
headers["Content-Type"] = "application/json"
payload = {
"intent": "buy",
"purchase_country": country,
"purchase_currency": currency,
"locale": locale,
"order_amount": amount_cents,
"order_tax_amount": 0,
"order_lines": order_lines,
"merchant_reference1": str(lead_id),
"merchant_data": json.dumps({"kommo_lead_id": lead_id}),
"merchant_urls": {
"confirmation": f"https://your-service.com/klarna/confirm?lead_id={lead_id}",
"notification": f"https://your-service.com/klarna/push?lead_id={lead_id}"
}
}
response = requests.post(
f"{KLARNA_BASE_URL}/payments/v1/sessions",
headers=headers,
json=payload,
timeout=10
)
response.raise_for_status()
return response.json()
@app.route("/kommo/webhook", methods=["POST"])
def handle_kommo_webhook():
"""Обрабатывает webhook от Kommo при смене статуса сделки."""
data = request.json
leads = data.get("leads", {}).get("status", [])
for lead_event in leads:
lead_id = lead_event.get("id")
status_id = lead_event.get("status_id")
if status_id == KOMMO_STAGE_ID_AWAITING_PAYMENT:
# Получаем детали сделки из Kommo API
lead_data = get_kommo_lead(lead_id)
amount_cents = int(lead_data.get("price", 0)) * 100
# Определяем параметры по умолчанию (можно брать из кастомных полей)
order_lines = [{
"type": "physical",
"reference": f"LEAD-{lead_id}",
"name": lead_data.get("name", "Order"),
"quantity": 1,
"unit_price": amount_cents,
"total_amount": amount_cents,
"total_tax_amount": 0,
"tax_rate": 0
}]
session = create_klarna_session(
lead_id=lead_id,
amount_cents=amount_cents,
currency="EUR",
country="DE", # можно сделать динамическим
locale="de-DE",
order_lines=order_lines
)
# Сохраняем ссылку для оплаты в кастомное поле Kommo
# Для hosted payment page URL нужно отдельно сконструировать
# Здесь сохраняем session_id для дальнейшей обработки
payment_url = f"https://pay.klarna.com/eu/hpp/{session['session_id']}"
update_kommo_lead_field(lead_id, KOMMO_CUSTOM_FIELD_KLARNA_URL, payment_url)
add_kommo_note(lead_id, f"Klarna payment session создана. Ссылка для клиента: {payment_url}")
return jsonify({"status": "ok"}), 200
def get_kommo_lead(lead_id):
"""Получает данные сделки из Kommo API."""
url = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4/leads/{lead_id}"
headers = {"Authorization": f"Bearer {KOMMO_ACCESS_TOKEN}"}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return response.json()
Обработка webhook от Klarna
Klarna присылает callback на URL, который вы указали в merchant_urls.notification при создании сессии. Payload содержит event_id и объект session с текущим статусом.
Возможные значения status в объекте сессии:
COMPLETED- клиент прошёл авторизацию Klarna успешноFAILED- оплата не прошлаCANCELLED- клиент отменилTIMEOUT- сессия истекла (активна 48 часов)
Для полного цикла платежа после COMPLETED нужно создать order через POST /payments/v1/authorizations/{authorization_token}/order - authorization_token приходит в callback, если используется стандартный (не HPP) flow.
@app.route("/klarna/push", methods=["POST"])
def handle_klarna_webhook():
"""Обрабатывает статусный webhook от Klarna."""
lead_id = request.args.get("lead_id")
data = request.json
event_id = data.get("event_id") # для дедупликации
session_data = data.get("session", {})
status = session_data.get("status")
if not lead_id or not status:
return jsonify({"error": "missing params"}), 400
if status == "COMPLETED":
# Авторизация прошла - обновляем статус в Kommo
# Если используем authorization callback flow:
authorization_token = data.get("authorization_token")
if authorization_token:
# Создаём order в Klarna (обязательный шаг для финального захвата средств)
order_result = create_klarna_order(authorization_token, lead_id)
klarna_order_id = order_result.get("order_id")
add_kommo_note(
lead_id,
f"Klarna: оплата авторизована. Order ID: {klarna_order_id}. "
f"Средства будут захвачены после отгрузки."
)
else:
add_kommo_note(lead_id, "Klarna: сессия завершена успешно. Ожидайте подтверждения order.")
elif status == "CANCELLED":
add_kommo_note(lead_id, "Klarna: клиент отменил оплату.")
elif status == "FAILED":
add_kommo_note(lead_id, "Klarna: оплата отклонена (order.denied). Требуется уточнение условий.")
elif status == "TIMEOUT":
add_kommo_note(
lead_id,
"Klarna: сессия истекла (48 часов). Необходимо создать новую ссылку."
)
# Всегда возвращаем 2xx - Klarna ретраит при других статусах
return "", 204
def create_klarna_order(authorization_token, lead_id):
"""Создаёт order в Klarna после успешной авторизации."""
headers = get_klarna_auth_header()
headers["Content-Type"] = "application/json"
# Тело должно совпадать с параметрами сессии
payload = {
"merchant_data": json.dumps({"kommo_lead_id": lead_id})
}
response = requests.post(
f"{KLARNA_BASE_URL}/payments/v1/authorizations/{authorization_token}/order",
headers=headers,
json=payload,
timeout=10
)
response.raise_for_status()
return response.json()
Обновление карточки сделки в Kommo
Функции для записи кастомного поля и добавления заметки в Kommo:
def update_kommo_lead_field(lead_id, field_id, value):
"""Обновляет кастомное поле сделки в Kommo."""
url = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4/leads"
headers = {
"Authorization": f"Bearer {KOMMO_ACCESS_TOKEN}",
"Content-Type": "application/json"
}
payload = [{
"id": lead_id,
"custom_fields_values": [{
"field_id": field_id,
"values": [{"value": value}]
}]
}]
response = requests.patch(url, headers=headers, json=payload, timeout=10)
response.raise_for_status()
return response.json()
def add_kommo_note(lead_id, text):
"""Добавляет заметку (note) к сделке в Kommo."""
url = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4/leads/notes"
headers = {
"Authorization": f"Bearer {KOMMO_ACCESS_TOKEN}",
"Content-Type": "application/json"
}
payload = [{
"entity_id": lead_id,
"note_type": "common",
"params": {"text": text}
}]
response = requests.post(url, headers=headers, json=payload, timeout=10)
response.raise_for_status()
return response.json()
После этого менеджер видит в карточке сделки:
- Кастомное поле «Klarna Payment URL» - ссылку, которую нужно отправить клиенту
- Заметку с историей: когда создана сессия, когда подтверждена оплата, что делать при отказе
Проверка статуса order через Order Management API
Если нужно проверить статус order вне webhook-потока (например, по запросу менеджера), используется GET /ordermanagement/v1/orders/{order_id}:
def get_klarna_order_status(order_id):
"""Проверяет статус order в Klarna Order Management API."""
headers = get_klarna_auth_header()
response = requests.get(
f"{KLARNA_BASE_URL}/ordermanagement/v1/orders/{order_id}",
headers=headers,
timeout=10
)
response.raise_for_status()
order = response.json()
# Возможные статусы: AUTHORIZED, PART_CAPTURED, CAPTURED, CANCELLED, EXPIRED, CLOSED
return order.get("status"), order
Возможные значения status в Order Management API:
AUTHORIZED- средства зарезервированы, ещё не захваченыCAPTURED- средства захвачены (после отгрузки)CANCELLED- order отменёнEXPIRED- авторизация истекла (60 минут в playground, в production - дольше по договорённости с Klarna)CLOSED- завершён (полный рефанд или закрытие)
Обработка ошибок
Основные кейсы, которые нужно обработать явно:
order.denied - Klarna отклонила авторизацию клиента. Это не техническая ошибка - Klarna провела собственный риск-скоринг и отказала. В webhook придёт status: FAILED. Правильное действие: уведомить менеджера через заметку, предложить альтернативный способ оплаты.
Истечение авторизации - authorization token действует 60 минут в playground. Если вы не создали order за это время, токен недействителен. Решение: создавайте Klarna order сразу при получении authorization_token в callback, не откладывайте.
Истечение сессии - payment session активна 48 часов. Если клиент не перешёл по ссылке за это время, статус становится TIMEOUT. Нужно создать новую сессию.
Ошибка 401 при вызове API - неверные credentials или попытка использовать playground-credentials в production. Проверьте пару username/password и соответствие environment.
def safe_create_klarna_session(lead_id, amount_cents, **kwargs):
"""Создание сессии с обработкой ошибок."""
try:
session = create_klarna_session(lead_id, amount_cents, **kwargs)
return session, None
except requests.exceptions.HTTPError as e:
error_detail = e.response.json() if e.response else str(e)
add_kommo_note(
lead_id,
f"Ошибка создания Klarna-сессии: {e.response.status_code}. "
f"Детали: {error_detail}. Требуется ручное создание."
)
return None, error_detail
except requests.exceptions.Timeout:
add_kommo_note(
lead_id,
"Klarna API не ответил за 10 секунд. Повторите попытку или создайте ссылку вручную."
)
return None, "timeout"
Реальный кейс с цифрами
Komando-сервис интеграций Exceltic реализовал аналогичную схему для европейской SaaS-компании, продающей B2B-подписки в DACH-регион (Германия, Австрия, Швейцария) через Kommo.
До интеграции: менеджеры тратили 7-12 минут на каждый цикл «создать ссылку Klarna - скопировать - добавить в CRM - проверить статус». При 30-40 сделках в месяц с Klarna-оплатой это около 6 часов ручной работы ежемесячно.
После интеграции:
- Создание Klarna-сессии занимает 0 дополнительного времени менеджера - запускается автоматически при смене этапа
- Статус оплаты обновляется в карточке без проверки вручную
- Conversion rate для этапа «Ожидание оплаты» вырос с 61% до 74% - менеджеры стали быстрее реагировать на отказы Klarna и предлагать альтернативы
- 0 случаев «потерянной» Klarna-ссылки (раньше 2-3 в месяц)
Аналогичный подход работает и для подписочных моделей - подробнее в Kommo + Chargebee: управление подпиской из воронки.
Для кого подходит эта интеграция
Идеальный профиль:
- Компания продаёт в Европе (особенно DACH, Нидерланды, Скандинавия)
- Чек сделки от 500 EUR - BNPL начинает давать конверсионный прирост именно в этом диапазоне
- Команда продаж 3+ человек: при меньшем размере ручной процесс ещё терпим
- Kommo уже используется как основная CRM, и нет желания добавлять отдельный инструмент для платежей
Не подойдёт:
- Если вы работаете только с рынком США - там у Klarna меньше покрытие и конкуренция выше (Affirm, Afterpay)
- Если чек ниже 200 EUR - транзакционные издержки Klarna съедят маржу
- Если клиенты - физлица и нужен полноценный B2C checkout (тогда смотрите на Klarna Checkout, а не Merchant API для B2B)
Если ваш стек платёжных инструментов шире Klarna, посмотрите также на кастомные интеграции в Kommo - там разобраны общие паттерны подключения внешних сервисов.
Часто задаваемые вопросы
Нужен ли отдельный контракт с Klarna для использования Merchant API?
Да. Klarna Merchant API доступен только зарегистрированным мерчантам. Вам нужно пройти онбординг на merchants.klarna.com, подписать договор и получить API credentials (username + password). Процесс занимает от нескольких дней до нескольких недель в зависимости от страны регистрации бизнеса.
Klarna работает только для физлиц или для B2B тоже?
Klarna исторически позиционировалась как B2C BNPL, но в последние годы активно развивает B2B-направление (Klarna for Business) в Европе. Для B2B доступны те же API, но условия и лимиты обсуждаются с менеджером Klarna при онбординге.
Что происходит если клиент отказывается платить после авторизации Klarna?
Klarna берёт кредитный риск на себя. После того, как вы создали order (POST /payments/v1/authorizations/{token}/order), Klarna гарантирует выплату вам при условии соблюдения merchant agreement. Клиент рассчитывается с Klarna напрямую по своему графику.
Можно ли отправить клиенту ссылку на оплату по email, а не встраивать виджет на сайт?
Да, и это как раз наш кейс. Klarna Hosted Payment Page (HPP) даёт готовый URL, который можно отправить клиенту в письме или мессенджере без встраивания виджета. Именно HPP-подход используется в описанной интеграции.
Какова комиссия Klarna для мерчанта?
Klarna не публикует единую ставку - она зависит от объёма, страны и продуктового микса (Pay Later 30 days, Pay in 3, Financing). Обсуждается при онбординге. Ориентировочно 1,9-3,5% от суммы транзакции для европейских рынков.
Следующий шаг
Если ваша команда продаж регулярно теряет время на ручное создание Klarna-ссылок или статус оплаты по сделкам непрозрачен в Kommo - напишите нам. Разбираем ваш конкретный процесс бесплатно на 30-минутном звонке и предлагаем решение под ваш стек: Kommo + Klarna, дополнительные payment методы или смешанная схема с несколькими провайдерами.