REST API Wildberries + 1С:УТ: заказы за 20 минут

REST API Wildberries + 1С:УТ: заказы за 20 минут

Коротко: Интернет-магазин электроники подключил REST API Wildberries к 1С:Управление торговлей 11.5 через HTTP-сервис с автоматической загрузкой заказов, обновлением остатков и синхронизацией статусов. Время обработки одного заказа сократилось с 4 часов до 20 минут, количество ошибок ручного ввода упало на 94%, а операционные расходы на обработку снизились на 60%.

С чего всё началось: боль ручной обработки заказов

Представьте типичный день менеджера интернет-магазина, торгующего на Wildberries. Утро начинается с открытия личного кабинета маркетплейса, ручного копирования заказов в Excel, затем переноса данных в 1С, проверки остатков, формирования заданий на сборку и отправки статусов обратно. Четыре часа монотонного труда — и это только утренняя смена. При пиковых нагрузках (акции, распродажи) количество заказов вырастало до 300–500 в день, и команда физически не справлялась.

Именно с такой ситуацией столкнулся наш клиент — интернет-магазин электроники из Екатеринбурга с ассортиментом около 2 000 SKU. До интеграции процесс выглядел так:

  • Менеджер вручную скачивал отчёт из WB каждые 2–3 часа;
  • Переносил данные в 1С:УТ 11.5 вручную или через промежуточный Excel;
  • Проверял наличие товара на складе;
  • Формировал заказы поставщику при нехватке;
  • Вручную обновлял статусы в личном кабинете WB;
  • Дублировал информацию в мессенджер для склада.

Ошибки были неизбежны: пересортица, задвоение заказов, опоздания с обновлением статусов, штрафы от Wildberries за просрочку сборки. Решение было очевидным — полная автоматизация через REST API Wildberries и нативную интеграцию с задачи по 1С:ERP и 1С:УТ.

Как устроен REST API Wildberries: что нужно знать разработчику?

Wildberries предоставляет открытый REST API, документация к которому доступна на портале openapi.wb.ru. API разделён на несколько блоков, каждый из которых закрывает свою бизнес-задачу:

Блок APIНазначениеКлючевые методы
MarketplaceУправление заказами FBS/api/v3/orders, /api/v3/orders/new
StatisticsОтчёты по продажам/api/v1/supplier/orders, /api/v1/supplier/sales
ContentКарточки товаров/content/v2/get/cards/list
PricesУправление ценами и скидками/public/api/v1/info, /public/api/v1/prices
WarehousesОстатки на складах/api/v3/warehouses, /api/v3/stocks/{warehouseId}

Аутентификация осуществляется через Bearer-токен, который генерируется в личном кабинете WB в разделе «Настройки → Доступ к API». Токен передаётся в заголовке каждого запроса: Authorization: Bearer {ваш_токен}.

Важные особенности API, которые нужно учесть при проектировании интеграции:

  • Rate limiting: большинство методов имеют ограничение 60–300 запросов в минуту;
  • Пагинация: заказы возвращаются порциями, нужно обрабатывать поле next для курсорной пагинации;
  • Идемпотентность: повторный запрос на создание поставки с тем же ID не создаст дубль;
  • Формат дат: RFC 3339 (например, 2024-01-15T10:30:00Z).

Архитектура решения: как связать WB API и 1С:УТ?

Перед написанием кода команда разработчиков спроектировала архитектуру интеграции. Было рассмотрено три варианта:

  1. Прямая интеграция через HTTP-запросы из 1С — 1С сама опрашивает API WB по расписанию;
  2. Промежуточный брокер сообщений — отдельный сервис получает вебхуки от WB и кладёт их в очередь;
  3. Внешняя обработка + планировщик Windows — COM-объект запускается по расписанию.

Был выбран первый вариант как наиболее простой в поддержке: регламентное задание в 1С каждые 5 минут вызывает API WB, получает новые заказы и обрабатывает их. Для обновления остатков используется отдельное задание с интервалом 15 минут. Схема потоков данных:

1С:УТ (регламентное задание) → GET /api/v3/orders/new → парсинг JSON → создание документов «Заказ клиента» → резервирование товара → POST /api/v3/orders/stickers (получение этикеток) → обновление статуса сборки → PATCH /api/v3/orders/{orderId} (подтверждение).

Для хранения токена и настроек создали отдельный регистр сведений «НастройкиИнтеграцииWB» с полями: Токен, URLБазовый, ИдСклада, РежимОтладки, ДатаПоследнейЗагрузки. Это позволяет менять параметры без изменения кода.

Пошаговая реализация: код загрузки заказов из WB в 1С

Рассмотрим ключевые фрагменты реализации. Начнём с базового модуля HTTP-взаимодействия с API Wildberries.

Шаг 1. Функция выполнения HTTP-запроса к API WB


// Модуль: ОбщийМодуль.ИнтеграцияWildberries
// Функция выполняет HTTP-запрос к API Wildberries и возвращает десериализованный JSON

Функция ВыполнитьЗапросWB(Метод, МетодHTTP = "GET", ТелоЗапроса = Неопределено) Экспорт

	// Получаем настройки из регистра сведений
	Настройки = РегистрыСведений.НастройкиИнтеграцииWB.ПолучитьПоследнее();

	Если НЕ ЗначениеЗаполнено(Настройки.Токен) Тогда
		ВызватьИсключение "Токен API Wildberries не заполнен в настройках интеграции";
	КонецЕсли;

	БазовыйURL = "https://marketplace-api.wildberries.ru";
	Токен = Настройки.Токен;

	// Формируем HTTP-соединение
	ЗащищённоеСоединение = Новый ЗащищённоеСоединениеOpenSSL();
	Соединение = Новый HTTPСоединение(
		"marketplace-api.wildberries.ru",
		443,
		,
		,
		,
		30,
		ЗащищённоеСоединение
	);

	// Формируем заголовки запроса
	Заголовки = Новый Соответствие();
	Заголовки.Вставить("Authorization", "Bearer " + Токен);
	Заголовки.Вставить("Content-Type", "application/json");
	Заголовки.Вставить("Accept", "application/json");

	// Создаём объект запроса
	Запрос = Новый HTTPЗапрос(Метод, Заголовки);

	// Если есть тело запроса — устанавливаем его
	Если ТелоЗапроса <> Неопределено Тогда
		Запрос.УстановитьТелоИзСтроки(
			ФорматJSON(ТелоЗапроса),
			КодировкаТекста.UTF8,
			ИспользованиеByteOrderMark.НеИспользовать
		);
	КонецЕсли;

	// Выполняем запрос
	Попытка
		Если МетодHTTP = "GET" Тогда
			Ответ = Соединение.Получить(Запрос);
		ИначеЕсли МетодHTTP = "POST" Тогда
			Ответ = Соединение.ОтправитьДляОбработки(Запрос);
		ИначеЕсли МетодHTTP = "PATCH" Тогда
			Ответ = Соединение.Записать(Запрос);
		ИначеЕсли МетодHTTP = "PUT" Тогда
			Ответ = Соединение.Записать(Запрос);
		КонецЕсли;
	Исключение
		ЗаписьЖурналаРегистрации(
			"ИнтеграцияWB.ОшибкаЗапроса",
			УровеньЖурналаРегистрации.Ошибка,
			,
			,
			ОписаниеОшибки()
		);
		Возврат Неопределено;
	КонецПопытки;

	// Проверяем код ответа
	Если Ответ.КодСостояния <> 200 И Ответ.КодСостояния <> 204 Тогда
		ТекстОшибки = "API WB вернул код: " + Ответ.КодСостояния
			+ ". Метод: " + Метод
			+ ". Тело: " + Ответ.ПолучитьТелоКакСтроку();
		ЗаписьЖурналаРегистрации(
			"ИнтеграцияWB.ОшибкаОтвета",
			УровеньЖурналаРегистрации.Предупреждение,
			,
			,
			ТекстОшибки
		);
		Возврат Неопределено;
	КонецЕсли;

	// Десериализуем JSON-ответ
	ЧтениеJSON = Новый ЧтениеJSON();
	ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
	Результат = ПрочитатьJSON(ЧтениеJSON);

	Возврат Результат;

КонецФункции

// Вспомогательная функция сериализации объекта в JSON-строку
Функция ФорматJSON(Объект)
	ЗаписьJSON = Новый ЗаписьJSON();
	ЗаписьJSON.УстановитьСтроку();
	ЗаписатьJSON(ЗаписьJSON, Объект);
	Возврат ЗаписьJSON.Закрыть();
КонецФункции

Шаг 2. Загрузка новых заказов и создание документов в 1С:УТ


// Процедура загружает новые заказы WB и создаёт документы «Заказ клиента» в 1С:УТ

Процедура ЗагрузитьНовыеЗаказыWB() Экспорт

	// Получаем список новых заказов (статус "new")
	ОтветAPI = ИнтеграцияWildberries.ВыполнитьЗапросWB("/api/v3/orders/new");

	Если ОтветAPI = Неопределено Тогда
		Возврат;
	КонецЕсли;

	МассивЗаказов = ОтветAPI["orders"];

	Если МассивЗаказов = Неопределено ИЛИ МассивЗаказов.Количество() = 0 Тогда
		// Новых заказов нет — выходим
		Возврат;
	КонецЕсли;

	КоличествоСоздано = 0;
	КоличествоПропущено = 0;

	Для Каждого ДанныеЗаказа Из МассивЗаказов Цикл

		ИдЗаказаWB = Строка(ДанныеЗаказа["id"]);

		// Проверяем — не загружен ли уже этот заказ
		Если ЗаказУжеСуществует(ИдЗаказаWB) Тогда
			КоличествоПропущено = КоличествоПропущено + 1;
			Продолжить;
		КонецЕсли;

		// Создаём документ «Заказ клиента»
		Попытка
			СоздатьЗаказКлиентаИзWB(ДанныеЗаказа);
			КоличествоСоздано = КоличествоСоздано + 1;
		Исключение
			ЗаписьЖурналаРегистрации(
				"ИнтеграцияWB.ОшибкаСозданияЗаказа",
				УровеньЖурналаРегистрации.Ошибка,
				,
				,
				"Заказ WB " + ИдЗаказаWB + ": " + ОписаниеОшибки()
			);
		КонецПопытки;

	КонецЦикла;

	ЗаписьЖурналаРегистрации(
		"ИнтеграцияWB.ЗагрузкаЗаказов",
		УровеньЖурналаРегистрации.Информация,
		,
		,
		"Создано: " + КоличествоСоздано + ", пропущено дублей: " + КоличествоПропущено
	);

КонецПроцедуры

// Функция проверяет существование заказа по внешнему ID WB
Функция ЗаказУжеСуществует(ИдЗаказаWB)

	Запрос = Новый Запрос();
	Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ЗаказКлиента.Ссылка
		|ИЗ
		|	Документ.ЗаказКлиента КАК ЗаказКлиента
		|ГДЕ
		|	ЗаказКлиента.ВнешнийКодWB = &ВнешнийКодWB
		|	И НЕ ЗаказКлиента.ПометкаУдаления";

	Запрос.УстановитьПараметр("ВнешнийКодWB", ИдЗаказаWB);
	Результат = Запрос.Выполнить();

	Возврат НЕ Результат.Пустой();

КонецФункции

// Процедура создаёт документ «Заказ клиента» из данных API WB
Процедура СоздатьЗаказКлиентаИзWB(ДанныеЗаказа)

	НачатьТранзакцию();

	Попытка

		// Создаём новый документ
		Документ = Документы.ЗаказКлиента.СоздатьДокумент();
		Документ.Дата = ТекущаяДатаСеанса();

		// Заполняем внешний код WB (реквизит добавлен через конфигуратор)
		Документ.ВнешнийКодWB = Строка(ДанныеЗаказа["id"]);
		Документ.НомерWB = Строка(ДанныеЗаказа["orderUid"]);

		// Определяем контрагента «Wildberries» (создан заранее в справочнике)
		Документ.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию(
			"Wildberries", Истина
		);
		Документ.Организация = ПолучитьОсновнуюОрганизацию();
		Документ.Склад = ПолучитьСкладWB();
		Документ.ВалютаДокумента = Справочники.Валюты.НайтиПоКоду("643");

		// Заполняем адрес доставки из данных WB
		АдресДоставки = ДанныеЗаказа["address"];
		Если АдресДоставки <> Неопределено Тогда
			Документ.АдресДоставки = АдресДоставки["fullAddress"];
		КонецЕсли;

		// Добавляем товарные позиции
		МассивТоваров = ДанныеЗаказа["skus"];
		Если МассивТоваров <> Неопределено Тогда
			Для Каждого АртикулWB Из МассивТоваров Цикл

				// Ищем номенклатуру по штрихкоду WB
				Номенклатура = НайтиНоменклатуруПоШтрихкодуWB(АртикулWB);

				Если НЕ ЗначениеЗаполнено(Номенклатура) Тогда
					ВызватьИсключение "Номенклатура не найдена для SKU WB: " + АртикулWB;
				КонецЕсли;

				// Добавляем строку в табличную часть
				Строка = Документ.Товары.Добавить();
				Строка.Номенклатура = Номенклатура;
				Строка.Количество = 1;
				Строка.Цена = ДанныеЗаказа["convertedPrice"] / 100;
				Строка.Сумма = Строка.Количество * Строка.Цена;
				Строка.СтавкаНДС = Перечисления.СтавкиНДС.БезНДС;

			КонецЦикла;
		КонецЕсли;

		// Записываем и проводим документ
		Документ.Записать(РежимЗаписиДокумента.Проведение);

		ЗафиксироватьТранзакцию();

	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Синхронизация остатков: как не уйти в минус на маркетплейсе?

Одна из самых критичных задач — своевременное обновление остатков на Wildberries. Если товар закончился на складе, а WB не знает об этом, магазин получает заказ, который не может выполнить, и штраф за отмену. Мы настроили двустороннюю синхронизацию остатков каждые 15 минут.


// Процедура обновляет остатки на складе WB через API

Процедура ОбновитьОстаткиНаWildberries() Экспорт

	Настройки = РегистрыСведений.НастройкиИнтеграцииWB.ПолучитьПоследнее();
	ИдСклада = Настройки.ИдСкладаWB;

	// Получаем актуальные остатки из 1С через запрос к регистру накопления
	Запрос = Новый Запрос();
	Запрос.Текст =
		"ВЫБРАТЬ
		|	Остатки.Номенклатура КАК Номенклатура,
		|	Остатки.Номенклатура.ШтрихкодWB КАК ШтрихкодWB,
		|	Остатки.КоличествоОстаток КАК КоличествоОстаток
		|ИЗ
		|	РегистрНакопления.ТоварыНаСкладах.Остатки(
		|		,
		|		Склад = &СкладWB
		|	) КАК Остатки
		|ГДЕ
		|	Остатки.Номенклатура.ШтрихкодWB <> ""
		|УПОРЯДОЧИТЬ ПО
		|	Остатки.Номенклатура.Наименование";

	Запрос.УстановитьПараметр("СкладWB", ПолучитьСкладWB());
	Выборка = Запрос.Выполнить().Выбрать();

	// Формируем массив для отправки в WB API
	МассивОстатков = Новый Массив();

	Пока Выборка.Следующий() Цикл

		ЭлементОстатка = Новый Структура();
		ЭлементОстатка.Вставить("sku", Выборка.ШтрихкодWB);
		ЭлементОстатка.Вставить(
			"amount",
			Макс(0, Цел(Выборка.КоличествоОстаток))
		);
		МассивОстатков.Добавить(ЭлементОстатка);

	КонецЦикла;

	Если МассивОстатков.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	// Отправляем остатки порциями по 1000 (ограничение API)
	РазмерПорции = 1000;
	Начало = 0;

	Пока Начало < МассивОстатков.Количество() Цикл

		Конец = Мин(

Отправка остатков: завершение логики порционной выгрузки

После формирования массива остатков отправляем данные на Wildberries порциями по 1000 позиций — это ограничение API маркетплейса. Вот как выглядит финальная часть процедуры:

		Конец = Мин(
			Начало + РазмерПорции,
			МассивОстатков.Количество()
		);

		ПорцияОстатков = Новый Массив();
		Для Инд = Начало По Конец - 1 Цикл
			ПорцияОстатков.Добавить(МассивОстатков[Инд]);
		КонецЦикла;

		ТелоЗапроса = Новый Структура();
		ТелоЗапроса.Вставить("stocks", ПорцияОстатков);

		ОтправитьОстаткиНаWB(ИдСклада, ТелоЗапроса);

		Начало = Начало + РазмерПорции;

	КонецЦикла;

КонецПроцедуры

Найдите специалиста для решения этой задачи на koderion.ru

Автор: редакция Koderion. Обновлено: 10 мая 2026. Источники: Бухгалтерия.ру, Infostart, ИТС 1С.