Обмен Битрикса с 1С по CommerceML: как устроен протокол

Разбираем обмен не по галочкам в админке, а по проводу: пять HTTP-команд, структура import.xml и offers.xml, пошаговый импорт и точки расширения.

Дмитрий Мещеряков
Дмитрий Мещеряков
📅 2 октября 2026 г.📖 9 мин чтения

Обмен с 1С — единственная подсистема Битрикса, которую большинство разработчиков никогда не открывали. Её настраивают галочками, а когда она ломается, лечат тем же способом: снимают и ставят галочки обратно, чистят кэш, перезапускают обмен и ждут. Иногда помогает.

Между тем внутри нет ничего мистического. Это HTTP-протокол из пяти команд и XML-файл с кириллическими тегами. Разработчик, который один раз посмотрел на обмен через curl, чинит типовую проблему за двадцать минут вместо двух дней — просто потому, что видит, где именно оборвалась цепочка.

Эта статья — про провод, а не про админку. Что 1С отправляет, что Битрикс отвечает, где лежат файлы и в какой момент можно вмешаться.

Что такое CommerceML

CommerceML — это открытый XML-стандарт обмена коммерческой информацией, разработанный фирмой «1С» для передачи каталогов, цен, остатков и заказов между учётной системой и сайтом. Битрикс работает со второй версией стандарта: корневой элемент называется КоммерческаяИнформация, а все теги внутри написаны по-русски.

Кириллица в тегах смущает, но у неё есть практическое следствие: XML читается глазами без документации. Открыв import.xml, вы сразу понимаете, что <Артикул> — это артикул, а <ЗначенияРеквизитов> — дополнительные поля товара. Для отладки это дороже, чем кажется.

💡 Совет

Версия схемы важна. В атрибуте ВерсияСхемы корневого элемента 1С указывает версию CommerceML — 2.03, 2.05, 2.08 и далее. Разные версии описывают одни и те же сущности слегка по-разному, и конфигурация 1С выбирает версию сама. Прежде чем спорить о том, «почему поле не приезжает», посмотрите на этот атрибут: возможно, поля в этой версии схемы просто нет.

Как устроен обмен: пять команд

Инициатор обмена — всегда 1С. Сайт ничего не запрашивает и не «забирает», он только отвечает. Вся точка входа — один скрипт:

text
/bitrix/admin/1c_exchange.php

Обмен каталогом идёт с параметром type=catalog, выгрузка заказов обратно в 1С — с type=sale. Второй параметр, mode, задаёт шаг.

text
1. GET ?type=catalog&mode=checkauth   → авторизация
2. GET ?type=catalog&mode=init        → параметры передачи
3. POST ?type=catalog&mode=file&filename=import.xml  → тело файла
4. GET ?type=catalog&mode=import&filename=import.xml → разбор файла
5. повтор шага 4, пока ответ = progress

Ответ всегда текстовый, и значение имеет первая строка: success, progress или failure. Всё остальное — детали для человека.

Шаг 1: checkauth

1С обращается с Basic Auth под пользователем сайта, у которого есть право на обмен. В ответ приходят три строки:

text
success
PHPSESSID
a1b2c3d4e5f6...

Вторая и третья строки — имя и значение сессионной куки: то, что PHP вернёт из session_name() и session_id(). Имя по умолчанию PHPSESSID, но оно настраивается, поэтому 1С обязана брать его из ответа, а не подставлять константу. 1С обязана подставлять её во все следующие запросы, иначе каждый шаг будет создавать новую сессию, а вместе с ней — новый прогресс импорта. Обмен в такой ситуации бесконечно ходит по кругу, не двигаясь дальше первого шага.

Шаг 2: init

text
zip=no
file_limit=1048576

zip говорит, принимает ли сайт архивы, file_limit — максимальный размер одной порции в байтах. Большой import.xml 1С режет на куски по file_limit и отправляет их последовательно с одинаковым filename, а Битрикс склеивает.

Шаг 3: file

Тело POST-запроса — сырые байты файла, без multipart и без формы. Файл ложится в /upload/1c_catalog/.

Шаг 4: import

Здесь начинается разбор. Битрикс читает XML, создаёт разделы, свойства и элементы — и не пытается сделать всё за один запрос. Отработав порцию, он отвечает:

text
progress
Импортировано 500 товаров из 12000

1С видит progress и повторяет тот же запрос. Битрикс продолжает с сохранённой позиции. И так, пока не вернётся success.

Понимание этого механизма решает половину проблем с обменом. Обмен не «висит» — он идёт шагами, и если шаг не укладывается в лимиты, цикл не двигается.

Как посмотреть обмен своими глазами

Самый полезный навык в этой теме — уметь пройти обмен руками. Никакого доступа к 1С для этого не нужно.

bash
# 1. Авторизация. -u — логин и пароль пользователя с правом на обмен
curl -s -u "exchange1c:password" \
  "https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=checkauth"
# success
# PHPSESSID
# 3f2a...

# 2. Параметры передачи — с полученной кукой
curl -s -b "PHPSESSID=3f2a..." \
  "https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=init"
# zip=no
# file_limit=1048576

# 3. Запуск импорта уже лежащего на сайте файла
curl -s -b "PHPSESSID=3f2a..." \
  "https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=import&filename=import.xml"
# progress

Три команды дают больше информации, чем час чтения форумов. Если checkauth возвращает failure — проблема в правах, и её видно сразу, а не через сообщение «обмен завершился с ошибкой» в 1С.

⚠️ Важно

Не запускайте mode=import на боевом сайте «чтобы посмотреть». Это настоящий импорт: он изменит товары, цены и активность элементов ровно так же, как если бы его инициировала 1С. Для экспериментов нужна копия сайта с копией базы — та же, на которой вы проверяете обновления.

Что внутри XML

import.xml — структура и товары

xml
<?xml version="1.0" encoding="UTF-8"?>
<КоммерческаяИнформация ВерсияСхемы="2.05" ДатаФормирования="2026-10-02">
  <Классификатор>
    <Ид>d5a9c1e4-...</Ид>
    <Группы>
      <Группа>
        <Ид>7b1f...</Ид>
        <Наименование>Смесители</Наименование>
      </Группа>
    </Группы>
    <Свойства>
      <Свойство>
        <Ид>a3c8...</Ид>
        <Наименование>Материал корпуса</Наименование>
      </Свойство>
    </Свойства>
  </Классификатор>
  <Каталог>
    <Товары>
      <Товар>
        <Ид>f4e2...</Ид>
        <Артикул>SM-1024</Артикул>
        <Наименование>Смеситель для кухни</Наименование>
        <Группы><Ид>7b1f...</Ид></Группы>
        <ЗначенияСвойств>
          <ЗначенияСвойства>
            <Ид>a3c8...</Ид>
            <Значение>Латунь</Значение>
          </ЗначенияСвойства>
        </ЗначенияСвойств>
      </Товар>
    </Товары>
  </Каталог>
</КоммерческаяИнформация>

Ключевая сущность здесь — <Ид>. Это GUID из 1С, и он же уезжает в поле XML_ID элемента или раздела инфоблока. Вся связь между двумя системами держится на нём: 1С не знает про ID элемента Битрикса и опознаёт товар только по GUID.

Отсюда правило, которое стоит запомнить до первой аварии: XML_ID элементов и разделов трогать нельзя. Ни руками в админке, ни скриптом миграции. Стёртый XML_ID означает, что следующий обмен не найдёт товар и создаст его заново — с новым ID, пустой статистикой и битыми ссылками в заказах.

offers.xml — цены и остатки

xml
<ПакетПредложений>
  <Предложения>
    <Предложение>
      <Ид>f4e2...#9a71...</Ид>
      <Цены>
        <Цена>
          <ИдТипаЦены>b2d4...</ИдТипаЦены>
          <ЦенаЗаЕдиницу>4990</ЦенаЗаЕдиницу>
          <Валюта>RUB</Валюта>
        </Цена>
      </Цены>
      <Количество>17</Количество>
    </Предложение>
  </Предложения>
</ПакетПредложений>

Обратите внимание на <Ид> предложения: GUID_товара#GUID_характеристики. Именно так торговое предложение привязывается к родительскому товару — Битрикс разбирает эту строку и записывает связь в служебное свойство CML2_LINK.

Разделение на два файла сделано ради скорости. import.xml тяжёлый, он несёт структуру и меняется редко. offers.xml лёгкий, его можно гонять хоть каждые пятнадцать минут — и именно так обычно и настраивают, чтобы остатки на витрине не расходились со складом.

Служебные свойства CML2

При первом обмене Битрикс сам создаёт в инфоблоке набор свойств с префиксом CML2_. Они выглядят как мусор в списке свойств, и их регулярно пытаются удалить «для порядка». Делать этого не надо — на них держится обмен.

Код свойстваЧто хранит
CML2_LINKСвязь торгового предложения с товаром
CML2_ARTICLEАртикул из 1С
CML2_BAR_CODEШтрихкод
CML2_MANUFACTURERПроизводитель
CML2_BASE_UNITБазовая единица измерения
CML2_TAXESНалоговые ставки
CML2_ATTRIBUTESРеквизиты, для которых нет отдельного свойства
CML2_TRAITSПризнаки товара
💡 Совет

CML2_ATTRIBUTES — свалка, а не поле. Туда падает всё, что 1С прислала в <ЗначенияРеквизитов> и чему Битрикс не нашёл соответствия. Если нужное значение из 1С «не приезжает», сначала загляните именно сюда: скорее всего, оно приехало, просто легло в общую кучу. Как вытащить его в нормальное свойство — тема отдельного разбора про маппинг полей.

Где вмешаться в импорт

Импорт в конце концов создаёт и обновляет элементы инфоблока, поэтому работают обычные события инфоблоков — те же, что описаны в разборе событий Битрикса:

php
<?php
// /bitrix/php_interface/init.php
use Bitrix\Main\EventManager;

EventManager::getInstance()->addEventHandler(
    'iblock',
    'OnAfterIBlockElementUpdate',
    function (&$arFields) {
        // Обмен приходит на свой скрипт — это самый надёжный признак контекста,
        // не зависящий от версии и от внутренних констант ядра
        $isExchange = str_contains(
            (string)($_SERVER['SCRIPT_NAME'] ?? ''),
            '/bitrix/admin/1c_exchange.php'
        );
        if (!$isExchange) {
            return;
        }
        // здесь — лёгкая работа: пометить элемент, положить ID в очередь
    }
);

Ключевое ограничение — цена обработчика. Он выполняется на каждом элементе. Обработчик, который делает один лишний запрос к базе, на каталоге в 50 000 товаров даст 50 000 запросов и превратит десятиминутный обмен в часовой. Поэтому в обработчике элемента складывают идентификаторы, а тяжёлую работу делают один раз после импорта:

php
<?php
EventManager::getInstance()->addEventHandler(
    'catalog',
    'OnSuccessCatalogImport1C',
    function () {
        // Импорт завершён: здесь пересчитываем, отправляем, сбрасываем кэш
        // Один раз на весь обмен, а не на каждый товар
    }
);
⚠️ Важно

Проверьте имя и сигнатуру события в своей версии. Набор событий модуля каталога между версиями Битрикса менялся, и обработчик, повешенный на несуществующее событие, не вызывает ошибки — он просто молча не срабатывает. Убедитесь, что обработчик реально выполняется, до того как повесите на него сброс кэша: обмен, который «прошёл успешно», но не сбросил кэш, оставит на витрине вчерашние цены, и узнаете вы об этом от покупателя.

Что ломается чаще всего

Обмен идёт по кругу и не завершается. 1С не сохраняет сессионную куку из checkauth либо каждый запрос создаёт новую сессию. Прогресс пишется в одну сессию, а следующий шаг читает другую — и начинает сначала.

failure без внятного текста. Смотрите вторую строку ответа и лог обмена, а не сообщение в 1С. Самое частое — нехватка прав на запись в /upload/1c_catalog/ или упавший по памяти шаг.

Товары продублировались. Кто-то изменил или очистил XML_ID. Битрикс не нашёл товар по GUID и создал новый. Восстанавливается только сопоставлением по артикулу и ручной склейкой — работа на день, поэтому XML_ID и не трогают.

Цены не обновились, хотя обмен успешен. Проверьте, что ИдТипаЦены из offers.xml сопоставлен с типом цены на сайте. Несопоставленный тип цены игнорируется тихо. Смежная классика — кэш каталога, который никто не сбросил после обмена; про политику кэширования каталога есть отдельный разбор.

Обмен съел память или упёрся в таймаут. Уменьшайте размер порции в настройках обмена. Увеличивать max_execution_time бессмысленно: шаговый механизм существует ровно для того, чтобы не упираться в лимиты, и правильный ответ — короче шаг, а не длиннее лимит. Как искать, во что именно упёрся PHP, разобрано в статье про диагностику PHP-FPM.

Итоги

Обмен с 1С перестаёт быть чёрным ящиком в тот момент, когда вы один раз прошли его руками через curl. Дальше диагностика превращается в механическую процедуру.

Сначала смотрите, что приехало. XML-файлы в /upload/1c_catalog/ — единственный достоверный источник. Если поля нет в XML, проблема в 1С, и обсуждать настройки сайта бесполезно.

Затем — на какой команде оборвалось. Пять шагов, у каждого свой характерный отказ. checkauth — права, file — доступ к папке и размер порции, import — лимиты PHP.

XML_ID — священная корова. Всё остальное в инфоблоке можно менять, это — нет.

Тяжёлую работу вешайте на завершение импорта, а не на элемент. Разница между этими двумя вариантами на большом каталоге измеряется часами.

И одно наблюдение, которое экономит больше всего времени: почти каждый раз, когда клиент говорит «обмен сломался», обмен работает. Ломается что-то одно на его краю — права у пользователя, сопоставление типа цены, кэш, который не сбросили. Протокол из пяти команд надёжен именно потому, что в нём нечему ломаться, и это хорошая новость: искать нужно не в нём.

Частые вопросы

Что такое CommerceML?

CommerceML — это открытый XML-стандарт обмена коммерческой информацией, разработанный фирмой «1С» для передачи каталогов, цен, остатков и заказов между учётными системами и сайтами. Битрикс работает с версией CommerceML 2 — той самой, где корневой элемент называется КоммерческаяИнформация, а имена тегов написаны кириллицей.

Куда 1С отправляет данные при обмене с Битриксом?

На скрипт /bitrix/admin/1c_exchange.php с параметрами type и mode. Обмен каталогом идёт с type=catalog, выгрузка заказов — с type=sale. Авторизация — Basic Auth под пользователем, у которого есть право на обмен; после успешного checkauth 1С получает из ответа имя и значение сессионной куки (по умолчанию PHPSESSID) и подставляет её во все последующие запросы.

Почему обмен с 1С обрывается на середине?

Потому что импорт пошаговый: Битрикс обрабатывает порцию данных, отвечает progress и ждёт повторного запроса. Если шаг не укладывается в max_execution_time PHP или в таймаут веб-сервера, соединение рвётся до того, как прогресс будет сохранён, и следующий запуск начинает тот же шаг заново. Лечится уменьшением размера порции в настройках обмена, а не увеличением таймаутов до бесконечности.

Чем import.xml отличается от offers.xml?

import.xml несёт структуру: классификатор групп, справочник свойств, единицы измерения и сами товары с их постоянными характеристиками. offers.xml несёт то, что меняется часто, — торговые предложения с ценами и остатками. Разделение сделано ради скорости: offers.xml можно гонять каждые 15 минут, не трогая тяжёлый каталог.

Как понять, что именно приехало из 1С?

Посмотреть XML-файлы, которые 1С загрузила на сайт: они лежат в /upload/1c_catalog/ до следующего обмена. Это единственный достоверный источник — админка показывает результат разбора, а не то, что было отправлено. Если товара нет в XML, спорить с Битриксом бессмысленно, проблема на стороне 1С.

Можно ли вмешаться в процесс импорта из 1С?

Да, через события. Импорт в конечном счёте создаёт и обновляет элементы инфоблока, поэтому работают обычные OnAfterIBlockElementAdd и OnAfterIBlockElementUpdate, а модуль каталога дополнительно бросает OnSuccessCatalogImport1C после завершения импорта. Обработчик, который делает тяжёлую работу на каждом элементе, замедлит обмен пропорционально числу товаров, поэтому массовые пересчёты вешают на завершение, а не на элемент.