Обмен 1С ↔ сайт через REST вместо CommerceML — когда оправдан

CommerceML — типовой обмен между 1С и сайтом, родной для Битрикса и многих CMS. Работает, но грузит партиями XML по cron, режет real-time и плохо переносит сложные витрины. REST-обмен — гибче и быстрее, но требует инженерных решений. Разбираем, когда REST окупается и как его собрать без вечных конфликтов остатков.

CommerceML — стандарт обмена между 1С и сайтом, который работает с 2000-х годов. Простой по смыслу: 1С выгружает XML с товарами и предложениями, сайт скачивает архив по HTTP и импортирует. В обратную сторону — заказы выгружаются с сайта аналогично. Битрикс умеет это из коробки, для большинства CMS есть готовые модули.

Проблема не в самом протоколе, а в его модели работы — batch-обмен по расписанию. Стоит магазину перейти из лоу-трафика в режим «остатки меняются каждые 10 минут, цены прыгают, маркетплейсы и склад одновременно тащат данные» — CommerceML начинает протекать. Тут на сцену выходит REST.

Что не так с CommerceML в 2026

Конкретные больные точки в активных проектах:

  • Полная выгрузка ради двух правок. Изменилась цена одного товара — выгружается архив на 80 000 SKU. Импорт час, сервер в нагрузке.
  • Cron-задержка. Cron раз в 30 минут — реалистичный потолок. Покупатель видит «есть в наличии» через 25 минут после того, как 1С зафиксировала отгрузку.
  • Конфликты при параллельных изменениях. Сайт принял заказ, через 2 минуты 1С выгрузила старый остаток — товар на витрине снова появился. Покупатель попадает в негатив.
  • Жёсткая структура XML. Любое расширение типа «гарантия 24 месяца» или «совместимые модели» в стандарт не лезет — пихается в служебные поля или отдельные обмены.
  • Цепочка «1С → файл → веб-сервер → импорт» хрупкая. Падение на любом шаге значит «синхронизации не было». Логи неинформативные, восстановление вручную.
  • Сложно дебажить. XML на 200 МБ через WinMerge — это боль.

Когда CommerceML достаточно

До REST переходить рано, если:

  • Каталог <3 000 SKU, обновления раз в день или реже.
  • Сайт на типовом Битриксе, нет планов разнести фронт.
  • Нет интеграций с маркетплейсами, складом, кассами в режиме real-time.
  • Команда разработки минимальная, поддержка через подрядчика на типовых задачах.

В этих сценариях CommerceML — рабочий вариант. Не чините то, что не сломано.

Когда REST окупается

Стоит переходить, если есть хотя бы три из списка:

  • Каталог >10 000 SKU и активно растёт.
  • Остатки меняются чаще, чем раз в час, и это важно для конверсии.
  • Магазин торгует на маркетплейсах — нужен единый источник остатков.
  • На сайте есть личный кабинет с балансом, статусом отгрузки, бонусами — это требует real-time.
  • Сайт построен не на Битриксе или на head-less архитектуре.
  • Нужно интегрировать платежи и доставку с событиями в 1С.
  • Команда разработки штатная или регулярный подрядчик.

Архитектура REST-обмена

Базовая схема — четыре слоя:

  1. 1С с HTTP-сервисами (BAS, http-сервисы из конфигуратора) или внешним REST-фасадом.
  2. Брокер сообщений или очередь (RabbitMQ, Kafka, Redis Streams, PostgreSQL LISTEN/NOTIFY).
  3. Service worker на бэкенде сайта, слушает очередь и применяет изменения.
  4. Sync state — таблица с маппингом ID 1С ↔ ID сайта, метками синхронизации, последним изменением.

Поток: изменение в 1С → событие в очередь → worker применяет на сайте → подтверждение → обновление sync state. В обратную сторону — заказы с сайта в очередь, 1С тащит из веб-сервиса или принимает webhook.

Реальное API

Пример набора эндпоинтов сайта, которые слушает 1С:

POST /api/sync/products/upsert
  { ext_id, name, price, currency, weight, vat,
    attributes: {...}, variants: [...] }
  → { id, ext_id, status: "ok" | "conflict", version }

POST /api/sync/stocks/batch
  { items: [ { ext_id, warehouse_code, qty } ] }
  → { applied: 384, conflicts: 0 }

POST /api/sync/orders/status
  { order_ext_id, status, tracking, updated_at }
  → { ok: true, version }

GET /api/sync/orders/since?ts=2026-06-12T00:00:00Z
  → { orders: [...] }

GET /api/sync/products/dirty?since=...
  → { items: [...] }

Все эндпоинты идемпотентные: повторный вызов с тем же ext_id и updated_at не должен ломать состояние.

Идемпотентность и версионирование

В асинхронной системе сообщения иногда дублируются, иногда теряются, иногда приходят в неправильном порядке. Без идемпотентности это разрушает данные.

Минимум, что нужно:

  1. Уникальный ext_id на стороне 1С. По нему мэппинг на сайт.
  2. updated_at или version на каждой записи. При апдейте — сравниваем: если входящий старше — отбрасываем.
  3. Журнал применённых событий (event_id из 1С). Перед обработкой — проверка «не было ли это уже».
  4. Optimistic locking на критичных полях (остаток): входящий апдейт идёт с if-match: version=N, если на сайте уже N+1 — отказ и пересчёт.

Самая болезненная точка — остатки

Конфликт сценария: на сайте оформлен заказ, остаток уменьшился. Параллельно 1С прислала обновление остатка из учёта (без учёта этого заказа). Если просто перезаписать — товар «появится» обратно, и сайт продаст его повторно.

Решение — модель «дельт и резервов», а не «текущего остатка»:

  • Сайт хранит остаток как: actual_qty - reserved_by_orders.
  • 1С шлёт дельты: «+15 пришло на склад», «-3 списано на отгрузку» — а не «теперь 47».
  • Сайт ведёт собственные резервы при оформлении заказа.
  • Раз в N минут — сверка: SELECT агрегата дельт и резервов = actual_qty с сайта.

Это сложнее, но единственный способ не задвоить продажу при высокой нагрузке. Альтернатива — централизация остатков в WMS, и 1С с сайтом получают данные оттуда.

Безопасность

REST-эндпоинты сайта будут торчать в интернет. Минимум:

  • TLS обязательно.
  • Аутентификация — JWT с коротким сроком или взаимный mTLS.
  • Rate limiting на эндпоинт по токену.
  • IP-whitelist для исходящих от 1С (если 1С на статическом IP).
  • Логирование всех изменений с маркером, какая система их инициировала.

Стек на стороне 1С

Три рабочих варианта:

  1. HTTP-сервисы 1С — встроены в платформу, пишут на встроенном языке. Удобно для серверных конфигураций, нагрузка средняя.
  2. 1С + внешний фасад (Python/Go-сервис между 1С и интернетом). 1С шлёт по локальной сети, фасад отвечает за rate limit, кэш, очередь.
  3. Шина данных (1С → DataLens-style middleware → сайт). Оправдано при 3+ системах в обмене.

Реалистичная оценка миграции

Перевод магазина с CommerceML на REST — не один спринт. Реалистичный план для каталога 30 000 SKU + 200 заказов в день:

  • Аудит текущего обмена и схемы данных — 1 неделя.
  • Доработка 1С под HTTP-сервисы и события — 3–6 недель.
  • Бэкенд сайта: API, sync state, worker, очередь — 4–8 недель.
  • Перевод остатков на модель дельт — 2–3 недели.
  • Параллельная работа CommerceML + REST 2–4 недели с реальным трафиком.
  • Полный переход, мониторинг 1 месяц.

Итого — 3–5 месяцев календарно, бюджет на команду 1С + бэкенд + DevOps. Дешёвых вариантов нет, попытки сделать «за месяц» обычно приводят к рассинхрону данных и эпическому откату.

Грабли

  • «Перевожу обмен, оставлю остатки на CommerceML». Гибрид CommerceML + REST на тех же сущностях — мина. Либо мигрируем всё, либо ничего.
  • Без очереди. Прямой sync 1С → API сайта без брокера. Сайт упал — события потеряны. Возврат к XML по cron.
  • Логика на стороне сайта дублирует 1С. Расчёт скидок, налогов, наценок в двух местах — источник вечных расхождений. Один источник истины, остальное — отображение.
  • Перенос всех справочников целиком. Сайту нужны не все 200 справочников из 1С. Перенесите только те, что показываются клиенту.
  • Отказ от sync state-таблицы. «Будем по timestamp» работает плохо, особенно когда 1С обновляет данные обратно во времени.

Вывод

CommerceML — рабочий стандарт для типовых интернет-магазинов на Битриксе с обновлениями раз в день. REST становится необходимым, когда подключаются маркетплейсы, real-time остатки и нестандартная архитектура сайта. Переход — 3–5 месяцев, нужна правильная архитектура: очередь, идемпотентность, остатки через дельты и резервы, sync state. Гибрид CommerceML + REST на тех же сущностях — категорически нет.