RetailCRM и n8n: три рабочих сценария автоматизации заказов и склада без участия менеджера
Что даёт связка RetailCRM + n8n и зачем она нужна
RetailCRM держит фронт: заказы прилетают, менеджеры их обрабатывают, клиенты видят статусы. Но между CRM и остальным миром, складской системой, СДЭК, Boxberry, 1С, всегда остаётся зазор. Кто-то вручную копирует трек-номера из личного кабинета перевозчика в карточку заказа. Кто-то утром сверяет остатки по телефону со складом. Вот этот зазор и закрывает n8n.
Связка работает так: RetailCRM хранит бизнес-логику и общается с менеджерами, n8n обеспечивает интеграционный слой между CRM, складом и службами доставки. Webhook от RetailCRM прилетает в n8n, тот дёргает API склада, получает актуальный остаток, возвращает данные обратно в заказ. Или забирает трек-номер из API СДЭК и прописывает его в RetailCRM без единого клика менеджера.
С технической стороны здесь всё сложилось удачно. RetailCRM API v5 стабилен и хорошо задокументирован. Это позволяет строить автоматизации, которые будут жить без постоянного ремонта. Параллельно n8n (версия 1.x) научился нормально работать с HTTP-нодами, условиями и трансформацией JSON, не требуя писать кастомный код на каждый чих.
Про on-premise скажу отдельно, потому что это не просто "фича для параноиков". Если ваш магазин работает с физлицами и хранит ФИО, телефоны, адреса доставки, вы под 152-ФЗ. Облачный iPaaS означает передачу персональных данных третьей стороне, а это требует отдельного юридического оформления, согласий и иногда прямо невозможно по договору с маркетплейсом. n8n разворачивается на вашем сервере, данные не покидают контур. Это закрывает вопрос compliance без юридических костылей.
Конкретный список задач, которые решаются в первую очередь:
- синхронизация складских остатков между WMS и RetailCRM по расписанию или триггеру
- автоматическое создание отгрузок в СДЭК при смене статуса заказа
- получение трек-номера от перевозчика и запись его в карточку заказа
- уведомления менеджеру в Telegram, если заказ завис в статусе дольше X часов
- передача данных о выкупах и отказах обратно в CRM для обновления статистики клиента
Ни одна из этих задач не требует программиста на постоянной основе. Один раз настроил в n8n, проверил на тестовых заказах, запустил. Если вы уже разбирали, как внешние сервисы подключаются к CRM-системам через готовые интеграции, принцип тот же, только здесь маршрутизацию берёт на себя n8n, а не коннектор.

Все три системы обмениваются данными через n8n как центральный маршрутизатор, а не напрямую друг с другом.
Архитектура интеграции: как это выглядит на практике
Если смотреть на схему целиком, получается три потока данных. Первый: RetailCRM отдаёт команду складу собрать заказ. Второй: склад сообщает, что заказ собран и готов к отгрузке. Третий: СДЭК получает заявку на забор, возвращает трек-номер, и этот номер оседает в RetailCRM. N8n стоит посередине и дирижирует всеми тремя.
Точка входа для первого потока, webhooks RetailCRM. Система умеет слать запросы на три типа событий: смена статуса заказа, создание заказа и изменение товарных позиций. Для интеграции со складом чаще всего нужен первый тип. Настраиваешь в RetailCRM webhook на статус «Подтверждён» (или как у тебя называется статус, после которого надо идти в сборку), указываешь URL вебхука в n8n, и дальше каждый раз при смене статуса n8n получает POST с телом заказа.
Дальше n8n решает, что делать с этим событием. Два варианта доставки задачи на склад, и выбор между ними зависит от того, что у тебя за WMS. Если склад умеет принимать REST, n8n делает HTTP-запрос напрямую: формирует тело с артикулами, количествами и ID заказа, шлёт в endpoint склада. Если склад работает через очередь сообщений, n8n подключается к RabbitMQ через встроенную AMQP-ноду и публикует сообщение в нужный exchange. Второй вариант лучше держит нагрузку: склад сам забирает задачи в своём темпе, и если WMS временно недоступна, сообщения не теряются.
Третий поток немного сложнее по структуре. Когда заказ готов к отгрузке, n8n обращается к СДЭК API v2 и создаёт заказ на доставку. В ответ приходит uuid, по которому потом нужно запросить трек-номер. Это отдельный запрос: СДЭК не отдаёт трек мгновенно, иногда проходит несколько минут. Так что здесь нужна либо пауза с последующим поллингом, либо отдельный scheduled-воркфлоу, который раз в N минут проверяет статус заказов без трек-номера.
Когда трек получен, n8n пишет его в RetailCRM через /api/v5/orders/{id}/edit. Поле для трека можно хранить в кастомном поле заказа или в стандартном delivery.trackNumber, если ты работаешь с объектом доставки напрямую. Я предпочитаю кастомное поле, потому что тогда виден весь путь: когда трек появился, какое значение было до этого, и можно добавить второй трек если посылка разделилась.
Схема выглядит линейной, но на практике в каждом потоке есть обработка ошибок. Webhook от RetailCRM мог прийти дважды (ретрай при таймауте), склад мог ответить 500, СДЭК мог вернуть ошибку валидации адреса. Про это отдельно.

Двусторонние стрелки означают, что n8n не просто отправляет команды, но и получает подтверждения обратно в RetailCRM.
Настройка RetailCRM API: получение ключей и нужные эндпоинты
Начну с того, что RetailCRM не даёт один мастер-ключ на всё. Права настраиваются отдельно при создании каждого ключа, и это правильно: не стоит давать интеграции с доставкой доступ к финансовым отчётам.
Где создать ключ. Заходите в «Настройки» → «Интеграция» → «API». Там кнопка «Создать API-ключ». Придумываете название (оно только для вас), выбираете методы. Для работы с заказами нужны четыре права: orders.read, orders.write, store.read, store.write. Меньше не даёте, больше не берёте без причины.
Сохранили ключ, скопировали строку. Второй раз она нигде не покажется, только пересоздавать.
Базовый URL выглядит так:
https://{ваш-домен}.retailcrm.ru/api/v5
Домен берёте из адресной строки вашего аккаунта. Версия v5 актуальна, v4 уже не стоит трогать: часть методов там задеприкейчена.
Три эндпоинта, которые покрывают 80% задач с заказами:
GET /orders, список с фильтрами по статусу, дате, менеджеру и ещё двум десяткам параметровPOST /orders/create, создание нового заказаPOST /orders/{id}/edit, обновление полей существующего
Кастомные поля чуть отдельная история. Сначала создаёте поле через интерфейс: «Настройки» → «Кастомные поля», указываете сущность (order, customer и т.д.) и код, например tracking_number. После этого поле доступно через эндпоинт /api/v5/custom-fields/order/tracking_number. Читаете и пишете через него же. Порядок важен: сначала интерфейс, потом API. Если пытаться создать поле через API без предварительной настройки, получите 404.
Пагинация. V5 работает через параметры page и limit. По документации API, за один запрос возвращается не более 100 записей. Если заказов больше, крутите page в цикле, пока в ответе не придёт pagination.totalPageCount.
Вот рабочий запрос: берём новые заказы, созданные с 1 мая 2026 года, по 50 штук на странице:
GET /api/v5/orders?filter[status]=new&filter[createdAtFrom]=2026-05-01&limit=50&page=1
X-API-KEY: your_api_key
Ключ передаётся именно в хедере X-API-KEY, не в теле и не в query-параметрах. Если передадите через URL, запрос формально пройдёт, но ключ осядет в логах сервера и nginx-е. Не делайте так.
Ответ придёт в JSON. Внутри: объект orders (массив), pagination с полями limit, totalCount, currentPage, totalPageCount. Этих четырёх чисел достаточно, чтобы написать нормальный цикл обхода без переплаты по запросам.
Первый сценарий: новый заказ попадает на склад без участия менеджера
Начну с конкретики. RetailCRM умеет слать webhook на любое событие заказа. Нас интересует order.create. Как только статус заказа меняется на «новый», CRM делает POST-запрос на адрес, который мы указали в настройках интеграции. Этот адрес и есть наша Webhook-нода в n8n.
Тело запроса выглядит примерно так:
{
"event": "order.create",
"data": {
"order": {
"id": 12345,
"status": "new",
"items": [
{ "offerId": "SKU-001", "quantity": 2, "price": 1500 }
],
"delivery": {
"address": { "city": "Москва", "street": "Ленина", "building": "1" }
}
}
}
}
n8n принимает его и сразу делает два дела в следующей ноде: извлекает позиции из data.order.items, адрес доставки из data.order.delivery.address и ID клиента. Всё это через простые выражения вида {{ $json.data.order.id }} прямо в интерфейсе без единой строки кода.
Дальше идёт HTTP Request-нода. Она формирует POST-запрос в складскую систему. Это может быть МойСклад, 1С с REST-обёрткой или собственный API. Структуру тела задаём сами под формат получателя. Главное, что n8n не просто пересылает исходный webhook, а трансформирует данные в нужную схему прямо внутри ноды через поле "Body Parameters" или JSON-режим.
Если склад принял задание и вернул ID сборки (скажем, { "taskId": "WH-9921" }), следующая нода записывает это значение в кастомное поле заказа через API RetailCRM. PATCH-запрос на /api/v5/orders/12345/edit с полем типа customFields[warehouse_task_id] = WH-9921. Теперь менеджер видит ID прямо в карточке заказа, не звоня на склад.
Параллельно (буквально параллельная ветка в том же workflow) Telegram Bot API получает сообщение вида: "Заказ #12345, Москва, ул. Ленина 1. Передан на склад, задание WH-9921". Ответственный менеджер видит это в личке или в групповом чате команды. Уведомление информационное, подтверждать ничего не нужно.
Теперь про ошибки. HTTP Request-нода в n8n поддерживает таймаут запроса. Ставим 10 секунд. Если склад не ответил, нода падает в ветку onError. Там два шага подряд: сначала сообщение в отдельный Telegram-чат с алертами ("Склад не ответил, заказ #12345, попытка 1"), потом Wait-нода на 5 минут и повторный HTTP Request. Количество попыток ограничиваем через счётчик в переменной workflow, чтобы не получить бесконечный цикл при реальном падении API склада.
Весь сценарий занимает 6-8 нод в n8n. Менеджер в процессе не участвует вообще. При нормальной работе всех API и сетевой связности задание попадает на склад очень быстро, за секунды, хотя реальная задержка зависит от времени отклика участвующих систем.

Пять узлов покрывают полный цикл: приём события, преобразование данных, запрос к API, ветвление по условию и отправку уведомления.
Второй сценарий: синхронизация остатков склада с RetailCRM
Склад живёт своей жизнью. RetailCRM живёт своей. И если их не синхронизировать каждые несколько минут, сайт будет принимать заказы на товары, которых физически нет, а менеджеры будут объяснять клиентам, почему "в наличии" оказалось ложью.
Задача решается в n8n за один воркфлоу. Разберу по частям.
Откуда берём данные. Большинство складских систем умеют одно из двух: отдавать остатки через REST-эндпоинт или выгружать файл (CSV, JSON). Оба варианта n8n закрывает стандартными нодами без кастомного кода. HTTP Request для REST, Read Binary File или FTP-нода для файлов, потом нода JSON или Spreadsheet File для парсинга. Ничего лишнего.
Расписание. Schedule Trigger, интервал 15 минут. Для большинства розничных магазинов этого достаточно. Если склад высокооборотный и 15 минут это катастрофа, ставь 5, но тогда следи за лимитами API RetailCRM на стороне магазина.
Маппинг артикулов. Это самое неприятное место. Склад хранит товары под своими идентификаторами, RetailCRM под своими, и они почти никогда не совпадают. Нода Code на JavaScript позволяет написать маппер прямо внутри воркфлоу, без внешних сервисов:
// n8n Code-нода: маппинг артикулов склада в offerId RetailCRM
const skuMap = {
'ART-001': 'SKU-001',
'ART-002': 'SKU-002'
};
return items.map(item => ({
json: {
offerId: skuMap[item.json.article] || item.json.article,
quantity: item.json.stock,
purchasePrice: item.json.cost
}
}));
Если маппинг-таблица большая (сотни позиций), держи её в Google Sheets или PostgreSQL и подтягивай в начале воркфлоу отдельной нодой. Хардкодить 500 строк в Code-ноде, конечно, можно, но редактировать это потом будет больно. Кстати, задача двусторонней синхронизации данных между системами хорошо разобрана на примере amoCRM и Google Sheets с разбором типовых подводных камней: часть проблем с маппингом там универсальна.
Отправка в RetailCRM. Эндпоинт POST /api/v5/store/products/batch/edit принимает до 250 позиций за один запрос. Если товаров больше, перед HTTP Request ставь ноду Split In Batches с размером чанка 250. Каждый чанк уходит отдельным запросом.
Нулевые остатки. Это критичная точка, которую часто пропускают. Если quantity равен нулю, недостаточно просто передать 0. Нужно явно проставить status: 'not-available' в теле запроса, иначе RetailCRM может продолжать показывать товар как доступный. Добавь в Code-ноду проверку:
return items.map(item => ({
json: {
offerId: skuMap[item.json.article] || item.json.article,
quantity: item.json.stock,
purchasePrice: item.json.cost,
status: item.json.stock === 0 ? 'not-available' : 'available'
}
}));
Логирование. Каждый прогон должен оставлять след. После успешного batch-запроса пиши в Google Sheets или PostgreSQL: временную метку, сколько позиций обновлено, сколько ушло в not-available, был ли HTTP 200 или ошибка. Когда через неделю выяснится расхождение между фактическим складом и тем, что видит сайт, журнал позволит найти момент, где что-то пошло не так, за 2 минуты, а не за 2 часа ручной сверки.
Весь воркфлоу: Schedule Trigger → HTTP Request (склад) → Code (маппинг + статусы) → Split In Batches → HTTP Request (RetailCRM) → нода для логирования. Шесть нод. Работает.

Расписание каждые 15 минут выбрано как баланс между актуальностью остатков и нагрузкой на API RetailCRM.
Третий сценарий: автоматическая передача заказов в СДЭК и получение трек-номеров
СДЭК API v2 работает по OAuth2. Без токена никаких запросов. Первым делом нода "Get Token" делает POST на https://api.cdek.ru/v2/oauth/token с grant_type=client_credentials и вашими client_id / client_secret из личного кабинета СДЭК. Токен живёт 3600 секунд, так что на каждый прогон workflow я обновляю его заново, а не кеширую.
// Нода: Get CDEK Token
// Method: POST
// URL: https://api.cdek.ru/v2/oauth/token
// Body (Form-Urlencoded):
grant_type=client_credentials
&client_id={{$env.CDEK_ID}}
&client_secret={{$env.CDEK_SECRET}}
CDEK_ID и CDEK_SECRET живут в Environment Variables n8n, не в теле workflow. Если воркфлоу когда-нибудь окажется в git-репозитории или коллеге на почте, учётные данные не утекут.
Готового коннектора СДЭК в n8n нет и в 2026 году не появилось. Только HTTP Request ноды. Это даже удобнее: полный контроль над заголовками и телом запроса без магии под капотом.
Создание заказа
После получения токена следующая нода формирует POST /v2/orders. Минимальное тело, которое СДЭК принимает без ошибок:
{
"tariff_code": 137,
"recipient": {
"name": "Иванов Иван",
"phones": [{ "number": "+79001234567" }]
},
"to_location": {
"city": "Москва",
"address": "ул. Ленина 1"
},
"packages": [
{
"number": "1",
"weight": 500,
"length": 20,
"width": 15,
"height": 10
}
]
}
Тариф 137 (Посылка склад-дверь). Все реальные поля: имя, телефон, город, адрес, вес в граммах, габариты в сантиметрах. Заголовок Authorization:
Bearer {{$node["Get Token"].json.access_token}}
СДЭК ответит объектом с полем entity.uuid. Трек-номера в этом ответе ещё нет. Это особенность API: заказ создаётся асинхронно, и tracking_number появляется обычно через 1-5 минут.
Polling до получения трек-номера
Здесь подключается петля. В n8n я строю её через ноду Wait (2 минуты) и IF-проверку: если tracking_number пустой, возвращаемся на GET /v2/orders/{uuid}, иначе идём дальше.
// Нода: Check Tracking
// Method: GET
// URL: https://api.cdek.ru/v2/orders/{{$node["Create Order"].json.entity.uuid}}
// Headers: Authorization: Bearer {{$node["Get Token"].json.access_token}}
Ответ содержит entity.statuses и, когда СДЭК готов, entity.cdek_number (это и есть трек-номер). Прогонять polling больше 10 итераций смысла нет. Если за 20 минут трек не появился, нода отправляет уведомление в Telegram-чат менеджерам и завершает цикл с ошибкой.
Запись трек-номера в RetailCRM
Когда cdek_number получен, HTTP Request нода пишет его в кастомное поле заказа в RetailCRM через PATCH /api/v5/orders/{id}. Поле создаёте заранее в настройках CRM, тип string, код например cdek_track.
Отдельный момент: если заказы в RetailCRM поступают через API с полем delivery, убедитесь, что структура соответствует схеме нового модуля СДЭК. Старый модуль принимал плоский объект, новый ожидает вложенный deliveryService с кодом cdek. Путаница в схемах ломала интеграцию у нескольких команд, с которыми я разбирал этот кейс.
Уведомление клиенту
Трек-номер сразу уходит клиенту через следующую ноду. Не через менеджера, не "когда руки дойдут". SMS через смс.ру или письмо через SendGrid, шаблон с переменной {{tracking_number}} и ссылкой на отслеживание https://www.cdek.ru/ru/tracking?order_id={{tracking_number}}.
Менеджер об этом даже не думает. Workflow делает всё само.

Retry-логика защищает от временных сбоев API CDEK и не требует ручного перезапуска сценария.
Обработка ошибок и мониторинг флоу в production
Когда флоу падает в три часа ночи, узнать об этом нужно до того, как клиент напишет в поддержку. В n8n для этого есть Error Workflow: отдельный флоу, который автоматически запускается при любой необработанной ошибке в основном. Настраивается в Settings каждого флоу, буквально одно поле.
Минимальная конфигурация Error Workflow, которую я использую: Telegram-нода отправляет три вещи. Название упавшей ноды (из {{ $json.execution.error.node.name }}), текст ошибки и прямую ссылку на конкретное выполнение в n8n UI. По ссылке открываешь, видишь входные данные ноды в момент падения. Разбор занимает две минуты, а не двадцать.
Все HTTP-запросы к RetailCRM и СДЭК оберните в Try/Catch. Нода появилась в n8n 1.x и решает конкретную проблему: если из пакета 30 заказов один упал с 500-й ошибкой API, флоу не останавливается полностью. Ошибочный заказ уходит в ветку Catch, остальные 29 обрабатываются дальше. Без Try/Catch один кривой ответ от СДЭК кладёт весь batch.
Отдельная история с идемпотентностью при передаче в СДЭК. Сеть нестабильна, n8n может ретрайнуть запрос, и заказ создастся дважды. Защита простая: перед вызовом API СДЭК ищите uuid заказа в кастомном поле RetailCRM. Если поле уже заполнено, пропускаете создание и идёте дальше. Uuid пишите в кастомное поле сразу после успешного ответа от СДЭК, в том же выполнении. Это не теория, я видел дубли заказов
