Перейти к содержанию

Диагностика платежей в n8n: webhooks, idempotency и CRM

Обновлено: 2026-05-29

Открыть мой план

Короткий ответ

Платёжный webhook в n8n нужно проектировать как финансовый журнал, а не как обычный “триггер для CRM”. Главная задача — принять событие один раз, связать его с заказом, сохранить исходный payload, вернуть успешный ответ провайдеру и только потом обновлять CRM, склад, Telegram и отчёты. Если workflow сразу делает всё подряд, любая задержка CRM, лимит API или ошибка маппинга превращает платёж в дубль, пропущенный заказ или ручной разбор.

Чем эта страница отличается от диагностики ЮKassa

Страница про ЮKassa должна решать частный кейс конкретного провайдера. Эта страница — общий чеклист архитектуры для любых платежных webhook: ЮKassa, CloudPayments, Stripe-подобные API, внутренний биллинг, кассовый модуль или кастомный backend. Здесь важны не названия полей, а принципы: статусы, идемпотентность, журнал, retry, алерты и ручная сверка.

Быстрая развилка по симптомам

Симптом Что обычно сломано Что исправлять
Оплата прошла, заказ не обновился нет связи payment → order metadata, order table, CRM field
Один заказ обновился дважды повтор webhook обработан как новый idempotency storage
Статус отмены перезатёр оплату нет таблицы разрешённых переходов state machine для заказа
Возврат не виден в отчётах возвраты смешаны с оплатами отдельный поток refund events
Провайдер повторяет доставку n8n не отвечает 2xx стабильно быстрый response и очередь
Менеджер не видит ошибку failed execution остаётся в n8n алерт в Telegram/почту

Минимальная схема надёжного платежного workflow

Разделите платежный процесс на пять логических блоков:

  1. Приём события — Webhook node, базовая валидация, быстрый ответ.
  2. Журналирование — запись event_id, payment_id, order_id, статуса, суммы и сырого payload.
  3. Идемпотентность — проверка, обрабатывалось ли такое событие раньше.
  4. Бизнес-решение — перевод заказа, уведомления, склад, чек-лист менеджера.
  5. Контроль — алерты, reconciliation, отчёт неизвестных статусов.

Такую схему можно реализовать даже без сложной инфраструктуры. Для MVP подойдёт Google Sheets или база CRM, но для боевых оплат лучше использовать Postgres с уникальными ключами.

Таблица статусов вместо IF-хаоса

Не разносите платежные статусы по десятку IF-нод. Лучше завести единую таблицу переходов. Она может быть в Code node, Postgres или отдельном JSON-конфиге.

{
  "payment.succeeded": {
    "order_status": "paid",
    "crm_stage": "Оплачено",
    "notify": ["sales", "ops"]
  },
  "payment.canceled": {
    "order_status": "payment_canceled",
    "crm_stage": "Оплата отменена",
    "notify": ["sales"]
  },
  "refund.succeeded": {
    "order_status": "refunded",
    "crm_stage": "Возврат",
    "notify": ["finance"]
  }
}

Плюс такого подхода — его легко проверить вручную. Если появляется новый статус, workflow не должен молча выбирать “ветку по умолчанию” и портить заказ. Неизвестное событие сохраняется в журнал и отправляется в алерт.

Идемпотентность: где хранить и что считать дублем

Повторная доставка webhook — нормальная часть платёжных систем. Провайдер может повторить событие при таймауте, временной ошибке или невалидном ответе. Поэтому “дубль” — это не баг провайдера, а сценарий, к которому workflow обязан быть готов.

Практичные варианты хранения:

Хранилище Подходит для Минусы
Postgres production, много оплат нужна база и миграции
CRM custom field малый поток, всё в CRM сложно хранить сырой payload
Google Sheets быстрый старт лимиты, гонки, ручные правки
Redis временная защита от повторов не заменяет финансовый журнал

Ключ события должен включать стабильный идентификатор объекта и тип события. Если использовать только order_id, можно случайно заблокировать возврат после оплаты. Если использовать только event, все успешные оплаты станут “одинаковыми”.

Как не потерять платёж из-за CRM

CRM — не источник истины для оплаты. CRM может быть недоступна, вернуть 429, принять не все поля или изменить API. Поэтому порядок безопаснее такой:

  1. Платёжное событие записано в финансовый журнал.
  2. Заказ найден по order_id или payment_id.
  3. CRM обновлена.
  4. Результат CRM-обновления записан отдельно.
  5. При ошибке CRM создаётся retry-задача или алерт.

Если CRM недоступна, платежный журнал всё равно должен показать: деньги пришли, заказ найден, обновление CRM не выполнено. Тогда оператор чинит интеграцию, а не ищет платёж “в воздухе”.

Retry и rate limit

Для исходящих HTTP Request в n8n используйте Retry on Fail и разумные задержки, но не включайте бесконечные повторы. Платёжные действия должны быть предсказуемыми: 2–3 попытки, запись ошибки, алерт, ручной повтор после анализа. Если провайдер или CRM возвращает 429, лучше добавить batching/Wait, а не запускать сотни одновременных запросов.

Отдельно проверьте, какие действия можно безопасно повторять. Уведомление менеджера можно повторить, но создание возврата или повторный запрос на списание — только с ключом идемпотентности и журналом.

Контрольная сверка раз в день

Даже хороший webhook не заменяет сверку. Сделайте отдельный scheduled workflow:

  • взять заказы за последние 24 часа;
  • получить актуальные платежные статусы из API провайдера;
  • сравнить с CRM;
  • найти расхождения;
  • отправить короткий отчёт финансовому или ответственному менеджеру.

Это особенно важно, если бизнес использует несколько каналов оплат, ручные возвраты или менеджеры могут менять статус заказа руками.

FAQ

Почему нельзя сразу обновлять CRM из платежного webhook?
Можно, но рискованно. Если CRM зависнет, webhook может не получить успешный ответ, а провайдер повторит событие. Лучше сначала принять и записать событие, затем обновлять CRM отдельным шагом.

Какой статус заказа считать финальным?
Финальность зависит от провайдера и бизнес-процесса. Обычно succeeded означает успешную оплату, но возвраты и отмены нужно обрабатывать отдельными событиями, а не перетирать историю.

Что делать с неизвестным платежным событием?
Не менять заказ автоматически. Сохранить payload, отправить алерт и добавить новый статус в таблицу переходов после проверки.

Где хранить сырой payload?
В журнале событий: Postgres, отдельная таблица, защищённое хранилище. Не храните в открытых логах секреты и лишние персональные данные.

Как проверить, что дублей больше не будет?
Отправьте один и тот же payload дважды. Первый запуск должен изменить заказ, второй — попасть в ветку “уже обработано”.