Выгрузка каталога на маркетплейсы — это половина интеграции, и обычно та, которую делают первой. Карточки заполнены, цены едут, модерация пройдена. Дальше начинается вторая половина, про которую на старте не думают: заказы с площадок надо получать в учётную систему, а остатки отдавать обратно — причём быстро и по всем складам сразу. Пока продаж десять в неделю, это переживается копированием руками. На сотне в день копирование заканчивается оверселлингом, отменами и штрафами. Разберём, как устроено обратное направление и где оно ломается.
FBO и FBS: почему это разные интеграции
Площадки работают по двум принципиально разным схемам, и от выбора схемы зависит почти весь объём работ.
- FBO — товар заранее лежит на складе площадки. Вы отгружаете партию, дальше площадка сама собирает, упаковывает и доставляет. В учёте это перемещение на склад-маркетплейс и потом отчёт о продажах
- FBS — товар лежит у вас. Площадка присылает сборочное задание на каждый заказ, вы собираете, печатаете этикетку и передаёте в доставку в отведённое окно
- realFBS и его аналоги — товар у вас и доставку тоже делаете вы, площадка только приводит покупателя
Для учётной системы FBO проще: остатки на складе площадки живут отдельной сущностью, а продажи приходят отчётом за период. Весь риск оверселлинга берёт на себя площадка. FBS сложнее на порядок: один и тот же физический остаток продаётся одновременно на сайте, на Ozon, на Wildberries и в офлайн-точке. Любая задержка синхронизации означает проданный товар, которого нет.
Главный риск FBS — не техническая ошибка, а время. Остаток, актуальный двадцать минут назад, уже может быть неправильным, и отменять заказ придётся вам, а не площадке.
Что отдают площадки по API
Каждая площадка имеет свой Seller API с токеном из личного кабинета продавца. Логика похожа, названия разные, и это главная причина, по которой универсального коннектора «на все маркетплейсы» не бывает.
Ozon Seller API. Авторизация двумя заголовками: Client-Id и Api-Key. Новые отправления забираются методом списка отправлений FBS с фильтром по статусу и периоду. Жизненный цикл отправления идёт по статусам вида awaiting_packaging, awaiting_deliver, delivering, delivered, cancelled. Ключ отправления — posting_number, и именно он, а не номер заказа, однозначно определяет то, что надо собрать: один заказ может разъехаться на несколько отправлений.
Wildberries Marketplace API. Работа идёт не с заказами, а со сборочными заданиями: отдельный метод отдаёт новые задания, другой — задания за период со статусами. Задания собираются в поставку, поставка закрывается, после закрытия печатается её штрихкод. Идентификатор задания приходит в поле вида id, артикул продавца — в vendorCode, и связка с номенклатурой держится именно на нём.
Яндекс Маркет. API организован вокруг кампании: заказы запрашиваются по идентификатору кампании, статусы меняются переводом заказа в следующее состояние с указанием подстатуса. Отдельно живёт управление остатками и ценами.
Практический вывод из этого разнообразия: интеграция пишется не «с маркетплейсами», а с каждой площадкой отдельно, и внутри приводится к своей общей модели — заказ, позиция, статус, склад. Иначе любое изменение в API одной площадки ломает код, обслуживающий все остальные. Если каталог уже уезжает на площадки, это тот же проект, что и выгрузка на маркетплейсы, но вторая его половина.
Сопоставление номенклатуры: где всё начинается
Ни одна площадка не знает ваших внутренних кодов. У Ozon это offer_id, у Wildberries vendorCode, у Маркета shopSku. В учёте это артикул номенклатуры, в МойСклад — code или externalCode, в 1С — артикул либо код по справочнику.
Правило одно: сопоставление должно быть по явному коду, который вы контролируете, и храниться в отдельной таблице соответствий. Не по названию, не по штрихкоду, не по «догадаться».
- Названия на площадке и в учёте расходятся всегда — там его правят маркетологи, здесь оно для накладной
- Штрихкод у фасовок и комплектов может совпадать или отсутствовать
- Один товар учёта может быть двумя карточками на площадке — например, поштучно и упаковкой по шесть
- Комплект на площадке может собираться из трёх разных позиций учёта, и остаток у него считается по минимуму
Последние два пункта — то, из-за чего интеграция «в один клик» обычно не подходит реальному магазину. Таблица соответствий с множителем количества решает оба случая: карточка упаковки отдаёт остаток, поделённый на шесть, и при продаже списывает шесть единиц. Без множителя остаток по упаковкам будет завышен в шесть раз.
Остатки: частота важнее точности
Остатки передаются методом обновления складских остатков: у Ozon и Маркета это отдельный метод с массивом позиций, у Wildberries остатки ставятся на конкретный склад продавца, идентификатор которого берётся из списка складов. Везде есть ограничение на размер пачки — порядка сотни позиций за запрос, и ограничение на частоту вызовов.
Отсюда конструкция, которая работает: не выгружать весь каталог по расписанию, а вести очередь изменений. Как только в учёте поменялся остаток позиции, она попадает в очередь; отдельный процесс раз в несколько минут забирает из очереди пачку и отправляет. Полная выгрузка всех остатков делается раз в сутки, ночью, как сверка — чтобы разойтись не могло даже при потерянных сообщениях.
Второй важный момент — сколько отдавать. Отдавать площадке весь физический остаток можно только если у вас нет других каналов продаж. Если есть сайт, розница и вторая площадка, применяют одно из двух правил:
- Буфер: отдаём остаток минус неснижаемый запас в одну-две единицы. Простое правило, теряет продажи по позициям с остатком один
- Распределение: на каждый канал отдаётся доля остатка по приоритету канала. Сложнее, но управляемо
- Общий пул с быстрой синхронизацией: отдаём всё, но синхронизируем за минуты и держим резерв на время сборки
Третий вариант — правильный с точки зрения выручки и самый требовательный к технике. Он работает только когда единый источник остатков есть на самом деле: не «в 1С и ещё в МойСклад», а одна система, из которой читают все остальные. Если учёт ведётся в двух местах, сначала чинится это, а потом уже интеграция — мы об этом подробно писали в разборе расхождения остатков между сайтом и 1С.
Площадка не прощает отмену по вине продавца. Поэтому в схеме FBS резерв под сборочное задание ставится в момент его получения, а не в момент отгрузки.
Заказ в учётную систему: какой документ создавать
Здесь чаще всего спорят, и спор не технический, а учётный. Три рабочих варианта:
- Заказ покупателя на каждое отправление, контрагент — площадка, затем реализация по факту передачи в доставку. Подходит, когда сборка занимает время и нужен резерв
- Сразу реализация, без заказа. Проще, но теряется этап резерва и промежуточные статусы
- Заказ покупателя на отправление плюс сводная реализация по отчёту площадки за период. Применяют, когда бухгалтерия работает по отчёту комиссионера
В МойСклад это заказ покупателя и отгрузка со ссылкой на него, в 1С — заказ клиента и реализация товаров. Контрагент в обоих случаях один на площадку, а не покупатель: персональные данные конечного покупателя площадка отдаёт в обезличенном виде и для учёта они не нужны.
Отдельная история с деньгами. Цена в документе — это цена продажи с площадки, а не то, что придёт на счёт. Комиссия, логистика, хранение и эквайринг вычитаются площадкой и приходят в отчёте продавца. Складывать их в цену позиции нельзя: разъедется вся товарная аналитика. Правильное место — отдельный документ на сумму вознаграждения площадки, который разносится по тому же периоду. В реализации при этом остаётся полная цена.
Идемпотентность: главное техническое требование
Любой обмен с площадкой периодически отдаёт одни и те же данные дважды: таймаут на нашей стороне, повтор запроса, перезапуск процесса, сдвиг окна выборки по дате. Если обработчик на каждое полученное отправление создаёт документ, в учёте появятся дубли заказов, двойное списание и неверные остатки.
Лечится это одним приёмом: внешний идентификатор отправления записывается в документ учёта и становится ключом. Перед созданием документа ищем его по этому ключу; нашли — обновляем статус, не нашли — создаём. В МойСклад для этого подходит поле внешнего кода или дополнительное поле, в 1С — реквизит с номером отправления. Поиск по сумме и дате ключом быть не может.
Там же решается вопрос с частичной обработкой. Если в задании пять позиций, а при создании документа три записались и обработчик упал, при повторе должны дописаться две оставшиеся, а не появиться второй документ. Поэтому создание документа и запись ключа делаются в одной транзакции, а разбор пачки идёт по одному отправлению за шаг с фиксацией результата.
Статусы, отмены и возвраты
Обратное направление статусов тоже нужно, и не только для красоты. Площадка должна знать, что задание собрано, иначе заказ отменится автоматически по истечении окна сборки. Передача статуса — это отдельный вызов API, и он обязан происходить после фактической сборки, а не вместе с созданием документа.
Сценарии, которые нужно продумать заранее, потому что они случаются каждую неделю:
- Покупатель отменил заказ до сборки — снимаем резерв, документ помечаем отменённым, остаток возвращается в пул
- Отмена после сборки и печати этикетки — товар физически отложен, нужно вернуть его на место отдельной операцией, иначе остаток будет занижен
- Невыкуп при доставке площадкой — товар возвращается на склад через несколько дней, в учёте это отдельное поступление, а не отмена
- Возврат по качеству — приходит отдельным потоком, часто вообще другим методом API, и в остаток попадать не должен, пока товар не проверен
- Частичная отмена — убрали одну позицию из трёх, документ надо править, а не создавать заново
Четвёртый пункт — самая частая причина расхождения учёта и склада по итогам месяца. Возврат по качеству, который автоматически вернулся в продаваемый остаток, превращается в заказ на товар, который лежит в коробке с биркой «брак».
Лимиты, ошибки и логи
У всех площадок есть ограничение частоты запросов, и при превышении приходит ответ с кодом 429. Это не ошибка интеграции, а штатная ситуация, которую обработчик обязан переживать: пауза с растущим интервалом и повтор, а не падение процесса. Кроме 429 стоит отдельно обрабатывать 401 и 403 — это истёкший или отозванный токен, и единственное верное поведение здесь — остановиться и уведомить, а не повторять запрос в цикле.
Журнал обмена пишется по каждому вызову: время, метод, тело запроса в сокращённом виде, код ответа, идентификаторы обработанных отправлений. Без журнала разбор любого спора с площадкой невозможен — а споры будут, потому что отмена по вине продавца считается в рейтинг и в деньги.
На мониторинг выносятся четыре вещи, и все они про время, а не про ошибки:
- Возраст последней успешной передачи остатков по каждой площадке — больше пятнадцати минут уже повод для уведомления
- Количество необработанных сборочных заданий старше часа
- Число позиций в очереди на обновление остатков — растущая очередь означает, что не успеваем
- Расхождение остатка в учёте и на площадке по итогам ночной сверки, в количестве позиций
Все четыре метрики полезны именно постоянным наблюдением: интеграция с маркетплейсами ломается не в день запуска, а через месяц, когда площадка меняет версию метода или в учёте появляется новый склад. Это та часть работы, которая живёт внутри поддержки, а не внутри проекта.
Чек-лист перед запуском FBS
- Определён единый источник остатков, остальные системы его только читают
- Таблица соответствий заполнена, у комплектов и фасовок задан множитель
- Выбрано правило отдачи остатка: буфер, распределение или общий пул
- Очередь изменений остатков работает, ночная полная сверка настроена
- Решено, какой документ создаётся на отправление и кто контрагент
- Комиссия площадки разносится отдельным документом, а не внутри цены
- Номер отправления записывается в документ и используется как ключ
- Резерв ставится при получении задания и снимается при отмене
- Отработаны отмена после сборки, невыкуп и возврат по качеству
- Обработчик переживает 429 паузой, а на 401 останавливается и уведомляет
- Журнал обмена пишется и хранится не меньше месяца
- Мониторинг возраста синхронизации и очереди настроен
- Проверено на тестовом контуре площадки до включения продаж
Мы делаем обмен с площадками в обе стороны — выгрузку каталога, приём сборочных заданий, передачу статусов и быструю синхронизацию остатков, — и приводим его к одному источнику данных. Что входит в работу, смотрите на страницах выгрузки на маркетплейсы и обмена с МойСклад. Если учёт ведётся в 1С, обратное направление настраивается в рамках интеграции с 1С. А если площадки уже работают параллельно собственному сайту, стоит заранее решить, как каналы делят спрос — об этом разбор сайта и маркетплейсов одновременно.