---
title: "amoCRM webhook в n8n: дедупликация событий | Nodbot"
source_url: "https://nodbot.ru/workflows/amocrm-webhook-deduplication/"
canonical_url: "https://nodbot.ru/workflows/amocrm-webhook-deduplication/"
language: "ru"
content_type: "WorkflowTemplate"
section: "workflows"
generated_at: "2026-05-30"
word_count_source: 1244
---

# amoCRM webhook в n8n: дедупликация событий через Postgres idempotency key

## AI summary

Problem/Solution-мануал для amoCRM webhooks в n8n: как построить idempotency key, записать его в Postgres с unique constraint, обработать событие один раз и безопасно отвечать на повторы.

## Best used for

Полноценный Problem/Solution-мануал для внедрения в n8n: импортировать workflow JSON, настроить webhook/API, проверить дубли, выполнить production-тесты и передать решение команде.

## Table of contents

- Проблема: почему amoCRM webhooks приходят повторно и ломают автоматизации
- Архитектура workflow для идемпотентной обработки
- Контракт входных данных (JSON Payload)
- Idempotency key и Postgres unique insert (Code Node + SQL)
- Готовый workflow JSON: скачать и импортировать
- Пошаговая настройка amoCRM webhook, n8n и Postgres
- Тесты перед production и проверка повторных событий
- Production-риски при обработке webhooks amoCRM
- Полезные ссылки и смежные workflow
- Критерии готовности

## Key topics

- amoCRM webhooks
- n8n idempotency
- Postgres unique constraint
- idempotency key
- ON CONFLICT DO NOTHING
- duplicate webhook
- CRM automation

## Source outline

amoCRM webhook в n8n: дедупликация событий через Postgres idempotency key ¶ Обновлено: 2026-05-30 Сохранить в мой план Открыть мой план Шаблон для внедрения Скачать workflow JSON Скачать test payload Скопировать curl Импортируйте JSON в n8n, подключите Postgres credential и замените endpoint бизнес-обработки. Содержание Проблема: почему amoCRM webhooks приходят повторно и ломают автоматизации Архитектура workflow для идемпотентной обработки Контракт входных данных (JSON Payload) Idempotency key и Postgres unique insert (Code Node + SQL) Готовый workflow JSON: скачать и импортировать Пошаговая настройка amoCRM webhook, n8n и Postgres Тесты перед production и проверка повторных событий Production-риски при обработке webhooks amoCRM Полезные ссылки и смежные workflow Критерии готовности Проблема: amoCRM webhooks могут приходить повторно, приходить почти одновременно или запускать несколько downstream-действий на одно обновление сделки. Если workflow отправляет уведомление, создаёт задачу или синхронизирует данные без идемпотентности, одно событие превращается в два письма, две задачи и два внешних API-вызова. Решение: webhook amoCRM в n8n должен сначала построить idempotency_key , затем атомарно записать его в Postgres с unique constraint и только после успешной вставки выполнять бизнес-логику. Повторное событие получает быстрый 200 OK , но не обрабатывается второй раз. Это production-паттерн для интеграторов: импортируемый workflow JSON, SQL-таблица, Code Node, тест повторного payload и чек-лист запуска. n8n принимает webhook amoCRM, строит idempotency key, вставляет его в Postgres и запускает бизнес-действие только один раз. Проблема: почему amoCRM webhooks приходят повторно и ломают автоматизации ¶ Webhook — это уведомление о событии, а не гарантия “ровно один раз”. CRM может повторить доставку, пользователь может быстро изменить одну и ту же сделку, а ваша логика может ответить медленно. Поэтому фильтр “я уже видел это событие” нельзя держать только в памяти n8n execution. Особенно опасны действия с побочным эффектом: отправка сообщения клиенту, создание задачи менеджеру, списание бонуса, обновление внешней системы. Повтор такого действия выглядит как баг интеграции, хотя первопричина — отсутствие идемпотентной обработки. Архитектура workflow для идемпотентной обработки ¶ Нода Роль Что проверить Webhook input Принимает webhook amoCRM Быстрый ответ, HTTPS, секрет/allowlist при возможности Build idempotency key Собирает ключ из account/entity/action/time Ключ стабилен для повтора и отличается для нового изменения Insert idempotency key Пишет ключ в Postgres PRIMARY KEY , ON CONFLICT DO NOTHING , отдельная таблица Process once Выполняет бизнес-действие Запускается только если insert вернул строку Respond Отвечает amoCRM Не раскрывает внутренние ошибки и токены Главный принцип: проверка и запись ключа должны быть одним атомарным действием. Нельзя делать “SELECT, потом INSERT” в двух шагах без блокировки — при параллельных событиях оба execution могут пройти проверку. Контракт входных данных (JSON Payload) ¶ Payload amoCRM зависит от типа сущности и события. Ниже пример обновления сделки. Для контактов и компаний добавьте отдельные ветки в Code Node, но сохраняйте одинаковый принцип ключа. { "account": { "id": 301001 }, "leads": { "update": [ { "id": 778899, "updated_at": 1780123456, "status_id": 12345, "pipeline_id": 67890 } ] } } Ключ должен включать не только ID сделки, но и действие или timestamp. Иначе разные изменения одной сделки будут считаться одним и тем же событием. Idempotency key и Postgres unique insert (Code Node + SQL) ¶ Code Node строит ключ, а Postgres гарантирует, что ключ будет принят только один раз. Это надежнее, чем хранить список обработанных событий в static data n8n. const event = $json.body ?? $json; const account = event.account?.id ?? event.account_id ?? 'unknown-account'; const leadUpdate = event.leads?.update?.[0]; const leadAdd = event.leads?.add?.[0]; const contactUpdate = event.contacts?.update?.[0]; const entity = leadUpdate ?? leadAdd ?? contactUpdate; const entityType = leadUpdate || leadAdd ? 'lead' : contactUpdate ? 'contact' : 'unknown'; const action = leadAdd ? 'add' : leadUpdate ? 'update' : contactUpdate ? 'update' : 'unknown'; const entityId = entity?.id ?? event.entity_id; const updatedAt = entity?.updated_at ?? event.updated_at ?? event.timestamp ?? ''; if (!entityId) { throw new Error('Cannot build amoCRM webhook idempotency key without entity id'); } const idempotencyKey = `amocrm:${account}:${entityType}:${entityId}:${action}:${updatedAt}`; return [{ json: { idempotency_key: idempotencyKey, account_id: String(account), entity_type: entityType, entity_id: String(entityId), action, event_time: String(updatedAt), raw_event_type: `${entityType}_${action}` } }]; SQL для таблицы и атомарной вставки: CREATE TABLE IF NOT EXISTS idempotency_keys ( key text PRIMARY KEY, source text NOT NULL, entity_type text NOT NULL, entity_id text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO idempotency_keys(key, source, entity_type, entity_id) VALUES ($1, 'amocrm', $2, $3) ON CONFLICT DO NOTHING RETURNING key; В n8n следующая нода должна проверять результат insert. Если строка не вернулась, это повтор: бизнес-действие пропускается, но webhook отвечает успешно. Готовый workflow JSON: скачать и импортировать ¶ Полный JSON лежит в архиве сайта и доступен по кнопке. После импорта замените Postgres credential и endpoint Process business action once на ваш внутренний обработчик. Скачать готовый workflow JSON Скачать тестовый payload { "name": "Nodbot - amoCRM webhook deduplication with Postgres", "nodes": [ { "name": "Webhook input", "type": "n8n-nodes-base.webhook", "purpose": "Принять webhook amoCRM" }, { "name": "Build idempotency key", "type": "n8n-nodes-base.code", "purpose": "Собрать стабильный ключ account/entity/action/updated_at" }, { "name": "Insert idempotency key", "type": "n8n-nodes-base.postgres", "purpose": "Вставить ключ через ON CONFLICT DO NOTHING" }, { "name": "Process business action once", "type": "n8n-nodes-base.httpRequest", "purpose": "Выполнить бизнес-логику только для нового ключа" }, { "name": "Respond to Webhook", "type": "n8n-nodes-base.respondToWebhook", "purpose": "Вернуть amoCRM быстрый безопасный ответ" } ], "connections": "Webhook → Build key → Insert key → Process once → Respond" } Если у вас уже есть отдельная таблица idempotency для webhooks других систем, используйте общий формат source + key + entity_type + entity_id . Тогда поддержку проще документировать. Пошаговая настройка amoCRM webhook, n8n и Postgres ¶ В amoCRM настройте webhook на production URL n8n и выберите только нужные события. В n8n импортируйте workflow JSON и подключите Postgres credential. Создайте таблицу idempotency_keys или примените SQL из статьи. Проверьте Code Node на событиях lead add, lead update и contact update, если они нужны. Настройте ветку: новая вставка запускает бизнес-действие, конфликт — возвращает “duplicate skipped”. Добавьте retention-политику: старые ключи можно удалять через 30–90 дней, если бизнес-процесс это допускает. В журнале видно, какое событие было принято впервые, а какие повторы безопасно пропущены. Тесты перед production и проверка повторных событий ¶ Отправьте один и тот же payload дважды. Первый запуск должен вставить ключ и выполнить бизнес-логику, второй — не должен делать повторное действие. Затем измените updated_at и убедитесь, что новое событие обрабатывается как отдельное. curl -X POST "https://YOUR-N8N-DOMAIN/webhook/amocrm-webhook-deduplication" \ -H "Content-Type: application/json" \ --data @amocrm-webhook-deduplication-payload.json Проверьте параллельный запуск: отправьте два одинаковых запроса почти одновременно. Если таблица настроена правильно, только один execution получит строку из RETURNING key . Production-риски при обработке webhooks amoCRM ¶ Ключ слишком грубый. Если использовать только lead_id , все обновления одной сделки будут пропущены. Ключ слишком детальный. Если включить случайные поля payload, повтор не распознается как повтор. SELECT перед INSERT. При параллельных событиях это создаёт гонку. Используйте unique insert. Бизнес-действие до записи ключа. Повтор уже успеет отправить сообщение или создать задачу. Webhook отвечает слишком медленно. Источник может повторить доставку, и нагрузка вырастет. Нет retention. Таблица idempotency растёт бесконечно и замедляет обслуживание. Полезные ссылки и смежные workflow ¶ Официальная документация amoCRM описывает формат webhooks и настройку HTTP-адресов для событий. Для хранения ключей используйте Postgres на том же production-контуре, где размещён n8n. Смотрите также внутри Nodbot: amoCRM в n8n — общая интеграционная страница. Postgres в n8n — подключение базы для idempotency. Webhook idempotency to Postgres — общий паттерн для любых источников. Tilda → amoCRM — защита лидов от дублей по телефону. Retry и DLQ для HTTP Request — обработка временных ошибок. Критерии готовности ¶ Одинаковый payload обрабатывается только один раз. Новое изменение той же сделки не пропускается как дубль. Параллельные одинаковые события не запускают два бизнес-действия. Postgres insert использует unique constraint и ON CONFLICT DO NOTHING . Webhook быстро отвечает источнику и не раскрывает внутренние ошибки. Есть retention-политика и владелец таблицы idempotency. Нужна надежная CRM-автоматизация? Nodbot настроит amoCRM webhooks, n8n, Postgres idempotency, retry/DLQ и мониторинг, чтобы одно событие не запускало бизнес-процесс дважды. Обсудить amoCRM webhook

## Test payload

```json
{
  "account": { "id": 301001 },
  "leads": {
    "update": [
      {
        "id": 778899,
        "updated_at": 1780123456,
        "status_id": 12345,
        "pipeline_id": 67890
      }
    ]
  }
}
```

## Key implementation snippet

```javascript
const event = $json.body ?? $json;
const account = event.account?.id ?? event.account_id ?? 'unknown-account';

const leadUpdate = event.leads?.update?.[0];
const leadAdd = event.leads?.add?.[0];
const contactUpdate = event.contacts?.update?.[0];

const entity = leadUpdate ?? leadAdd ?? contactUpdate;
const entityType = leadUpdate || leadAdd ? 'lead' : contactUpdate ? 'contact' : 'unknown';
const action = leadAdd ? 'add' : leadUpdate ? 'update' : contactUpdate ? 'update' : 'unknown';
const entityId = entity?.id ?? event.entity_id;
const updatedAt = entity?.updated_at ?? event.updated_at ?? event.timestamp ?? '';

if (!entityId) {
  throw new Error('Cannot build amoCRM webhook idempotency key without entity id');
}

const idempotencyKey = `amocrm:${account}:${entityType}:${entityId}:${action}:${updatedAt}`;

return [{
  json: {
    idempotency_key: idempotencyKey,
    account_id: String(account),
    entity_type: entityType,
    entity_id: String(entityId),
    action,
    event_time: String(updatedAt),
    raw_event_type: `${entityType}_${action}`
  }
}];
```

## Importable workflow structure

```json
{
  "name": "Nodbot - amoCRM webhook deduplication with Postgres",
  "nodes": [
    { "name": "Webhook input", "type": "n8n-nodes-base.webhook", "purpose": "Принять webhook amoCRM" },
    { "name": "Build idempotency key", "type": "n8n-nodes-base.code", "purpose": "Собрать стабильный ключ account/entity/action/updated_at" },
    { "name": "Insert idempotency key", "type": "n8n-nodes-base.postgres", "purpose": "Вставить ключ через ON CONFLICT DO NOTHING" },
    { "name": "Process business action once", "type": "n8n-nodes-base.httpRequest", "purpose": "Выполнить бизнес-логику только для нового ключа" },
    { "name": "Respond to Webhook", "type": "n8n-nodes-base.respondToWebhook", "purpose": "Вернуть amoCRM быстрый безопасный ответ" }
  ],
  "connections": "Webhook → Build key → Insert key → Process once → Respond"
}
```

## Retrieval hints

- Использовать HTML как canonical source.
- Markdown удобен для LLM-ответов, извлечения workflow-контракта, кода и чеклистов.
- Для ссылок пользователю отдавать canonical URL.
