<!-- source: https://nodbot.ru/integrations/shopify/; markdown: /llms/pages/generated/integrations-shopify.md; type: IntegrationGuide -->
---
title: "Shopify и n8n: заказы в CRM без дублей | Nodbot"
source_url: "https://nodbot.ru/integrations/shopify/"
canonical_url: "https://nodbot.ru/integrations/shopify/"
language: "ru"
content_type: "IntegrationGuide"
section: "integrations"
generated_at: "2026-05-30"
word_count_source: 1013
---

## AI summary

Problem/Solution-гайд по Shopify и n8n: как принимать order webhooks, проверять событие, обрабатывать заказ один раз и безопасно передавать его в CRM или склад.

## Best used for

Страница нужна интеграторам, product/engineering-командам и владельцам n8n, которые хотят внедрить связку без дублей, ручного хаоса и потери контекста.

## Key topics

- Shopify
- n8n
- webhook
- orders
- idempotency
- CRM
- ERP
- line items
- HMAC signature
- ecommerce automation

# Интеграция Shopify и n8n: заказы, webhooks и идемпотентность в CRM

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

Импортируйте JSON в n8n, замените credentials, URL API, project/list IDs, поля и лимиты под вашу инфраструктуру.

- Проблема и решение

- Архитектура workflow

- Контракт данных

- Code Node и проверки

- Готовый workflow JSON

- Пошаговая настройка

- Тесты перед production

- Production-риски

- Полезные ссылки

- Критерии готовности

Проблема: Shopify webhook может приходить повторно, а order update похож на новый заказ. Если n8n без проверки сразу создаёт сделку или строку в складе, появляются финансовые и операционные дубли.

Решение: Нужно принимать Shopify webhook как критичное событие: проверить topic, shop domain и подпись, собрать idempotency key по order_id/topic, нормализовать customer/line_items и только потом обновлять CRM или склад.


## Проблема: почему простая интеграция создаёт дубли и ручной хаос

Интеграция Shopify и n8n обычно начинается с задачи “передать заказ в CRM”. Но у ecommerce-сценариев больше рисков: повторная доставка webhook, возвраты, частичные оплаты, изменение адреса, тестовые заказы и разные статусы fulfillment.

Если workflow не различает order created, order paid, fulfilled и cancelled, команда может дважды отгрузить товар, создать две сделки или отправить лишнее уведомление клиенту. Поэтому эта страница фокусируется на order webhook, idempotency и понятном контракте для downstream-систем.


## Архитектура workflow для n8n

| Блок | Задача | Production-проверка |

| --- | --- | --- |

| Shopify Webhook | принимает order event | topic, shop, signature, JSON body |

| Validate event | проверяет topic/shop и собирает idempotency key | allowlist shops и topics |

| Normalize order | готовит customer, line_items, totals и shipping | валюта, статус оплаты, fulfillment |

| Check idempotency | проверяет order_id/topic в журнале | уникальный ключ в Postgres/CRM |

| Update CRM/ERP | создаёт заказ или обновляет статус | не повторять отгрузку |

| Respond / alert | подтверждает webhook и пишет ошибки | быстрый 2xx, alert и DLQ |

Для ecommerce нельзя считать все Shopify events одинаковыми. Обработка order paid и fulfillment updated должна быть отдельной от order created, иначе бизнес-действия повторятся.


## Контракт входных данных

```json
{
  "topic": "orders/paid",
  "shop_domain": "demo-store.myshopify.com",
  "id": 5812345678901,
  "name": "#10492",
  "email": "client@example.com",
  "created_at": "2026-05-30T10:00:00+03:00",
  "currency": "RUB",
  "financial_status": "paid",
  "fulfillment_status": null,
  "total_price": "12900.00",
  "customer": {
    "id": 998877,
    "first_name": "Иван",
    "last_name": "Петров",
    "phone": "+7 916 123-45-67"
  },
  "shipping_address": {
    "city": "Москва",
    "address1": "ул. Примерная, 10"
  },
  "line_items": [
    {
      "sku": "N8N-SETUP",
      "name": "Настройка интеграции",
      "quantity": 1,
      "price": "12900.00"
    }
  ]
}
```

В тестовом payload topic передан как поле для удобства. В production Shopify topic обычно приходит в headers, поэтому workflow должен читать и headers, и body.


## Code Node: нормализация, mapping и guard-условия

```javascript
const src = $json.body ?? $json;
const headers = $json.headers ?? {};
const topic = String(headers['x-shopify-topic'] ?? src.topic ?? '').trim();
const shop = String(headers['x-shopify-shop-domain'] ?? src.shop_domain ?? '').trim().toLowerCase();
const allowedTopics = ['orders/create', 'orders/paid', 'orders/fulfilled', 'orders/cancelled'];
const allowedShops = ['demo-store.myshopify.com'];
if (!allowedTopics.includes(topic)) return [{ json: { action: 'ignore', reason: 'topic_not_allowed', topic } }];
if (!allowedShops.includes(shop)) throw new Error(`Shopify shop is not allowed: ${shop}`);
const orderId = String(src.id ?? src.admin_graphql_api_id ?? '').trim();
if (!orderId) throw new Error('No Shopify order id');
const lines = Array.isArray(src.line_items) ? src.line_items.map(item => ({
  sku: String(item.sku ?? '').trim(),
  name: String(item.name ?? '').trim(),
  quantity: Number(item.quantity ?? 0),
  price: Number(item.price ?? 0)
})) : [];
return [{ json: {
  action: 'sync_order',
  idempotency_key: `shopify:${shop}:${topic}:${orderId}`,
  shop,
  topic,
  order_id: orderId,
  order_name: String(src.name ?? '').trim(),
  customer_email: String(src.email ?? src.customer?.email ?? '').trim().toLowerCase(),
  customer_phone: String(src.customer?.phone ?? src.phone ?? '').trim(),
  total_price: Number(src.total_price ?? 0),
  currency: String(src.currency ?? '').trim(),
  financial_status: String(src.financial_status ?? '').trim(),
  fulfillment_status: src.fulfillment_status ?? 'not_fulfilled',
  line_items: lines,
  crm_comment: `Shopify ${topic} ${src.name ?? orderId}`
}}];
```

Один и тот же order_id может участвовать в разных событиях: create, paid, fulfilled, cancelled. Ключ order_id без topic смешает статусы и может заблокировать нужное обновление.


## Готовый workflow JSON: скачать и импортировать

Скачать готовый workflow JSON Скачать тестовый payload

```json
{
  "name": "Nodbot - Shopify order webhook to CRM with idempotency",
  "nodes": [
    {
      "name": "Shopify Webhook",
      "type": "n8n-nodes-base.webhook",
      "purpose": "Принять order event"
    },
    {
      "name": "Validate Shopify event",
      "type": "n8n-nodes-base.code",
      "purpose": "Проверить topic/shop/signature"
    },
    {
      "name": "Normalize order",
      "type": "n8n-nodes-base.code",
      "purpose": "Собрать order contract"
    },
    {
      "name": "Check idempotency",
      "type": "n8n-nodes-base.postgres",
      "purpose": "Не обработать event дважды"
    },
    {
      "name": "Update CRM or ERP",
      "type": "n8n-nodes-base.httpRequest",
      "purpose": "Передать заказ"
    },
    {
      "name": "Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "purpose": "Вернуть 200"
    }
  ],
  "connections": "Shopify Webhook → Validate Shopify event → Normalize order → Check idempotency → Update CRM or ERP → Respond"
}
```


## Пошаговая настройка связки

- Создайте Shopify webhook только для нужных order topics.

- Включите проверку подписи или вынесите её в reverse proxy/Code Node.

- Импортируйте workflow JSON и замените shop allowlist, credentials и CRM endpoint.

- Определите отдельные правила для paid, fulfilled и cancelled.

- Проверьте повторную доставку одного webhook и отмену заказа.


## Тесты перед production

```bash
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/integration-shopify-n8n-order-webhook" \
  -H "Content-Type: application/json" \
  --data @integration-shopify-n8n-order-webhook-payload.json
```

- Повторный payload не создаёт дубль и возвращает тот же output key.

- Некорректный mapping останавливается до запроса к внешнему API.

- Пустые необязательные поля не ломают workflow.

- Ошибка API уходит в alert или DLQ с безопасным payload.

- Execution data не содержит секретов, токенов и лишних персональных данных.


## Production-риски

- Нет проверки подписи. Публичный webhook URL можно подделать.

- Все topics идут в один create. Отмена или fulfillment создаёт новую сделку вместо обновления.

- Idempotency только по order_id. Разные события одного заказа блокируют друг друга.

- Line items превращены в текст. Склад или ERP не сможет обработать SKU и количество.

- Ответ webhook ждёт CRM слишком долго. Лучше быстро подтвердить событие и отправить тяжёлую обработку в очередь.


## Полезные ссылки и смежные материалы

- Shopify Webhooks overview

- Shopify webhook topics

- Creating webhooks in Shopify admin

- Webhook signature validation

- Webhook idempotency to Postgres


## Критерии готовности

- Webhook topic, shop domain и signature проверяются до бизнес-логики.

- Idempotency key включает shop, topic и order_id.

- Line items сохраняют SKU, quantity и price структурно.

- Paid, fulfilled и cancelled имеют разные правила обработки.

- Ошибки CRM/ERP уходят в alert или DLQ без потери webhook.

Nodbot настроит Shopify + n8n: проверку webhook, idempotency, line items, статусы оплаты/отгрузки, CRM/ERP-sync, retry и мониторинг.
