Мок-API

Wildberries

Что покрыто в моке Wildberries, откуда взята спецификация и чем мок отличается от боевого API.

На этой странице · 7

У Wildberries API разложен по десятку хостов и по четырнадцати файлам спецификации. Это единственный сервис стенда, где X-APIStend-Upstream у разных методов разный, и единственный, где встречаются все пять глаголов.

Откуда взята спецификация

ЧтоЗначение
Источникdev.wildberries.ru/api/swagger/yaml/ru/ — отдаёт HTTP 498 (антибот)
Зеркалоgithub.com/eslazarev/wildberries-sdk (лицензия зеркала MIT)
Лицензия самой спецификациине объявлена
Снимок2026-09-07
Состав14 YAML-файлов; 05-orders-dbs.yaml исключён как дубль 05-dbs.yaml

Целостность снимка зафиксирована: specs/wildberries/MANIFEST.tsv содержит sha256 каждого файла.

Что покрыто

316 методов на момент написания: 86 с примером ответа, 181 собирается по схеме, 49 отдают пустой конверт. Числа живые — актуальные показывает /api/services и каталог.

Группы каталога повторяют файлы спецификации: Товары, Заказы FBS, DBS, DBW, Поставки FBW, Самовывоз, Маркетинг и продвижение, Общение с покупателями, Аналитика и данные, Отчёты, Тарифы, Документы и бухгалтерия, Общее. «Wildberries Цифровой» вынесен отдельной группой с пометкой «отдельный продукт»: он живёт на своём хосте и требует токена другой категории.

Особенности вызова

Авторизация — заголовок Authorization с токеном, без префикса Bearer (шлюз принимает и с префиксом):

curl -s localhost:8080/wb/api/v3/warehouses -H "Authorization: $KEY"

Глагол значим. Распределение по методам: 139 POST, 135 GET, 16 PUT, 15 PATCH, 11 DELETE. Запрос с чужим глаголом вернёт 404 и подсказку X-APIStend-Did-You-Mean.

Чтение остатков — это POST

/api/v3/stocks/{warehouseId} работает по трём глаголам сразу: POST — получить остатки, PUT — обновить, DELETE — удалить. Клиент, который запрашивает остатки через GET, в бою получит ошибку; мок ведёт себя так же.

Лимиты и ошибки

Профиль — до 300 запросов в минуту, ёмкость ведра 300, при превышении 429 и X-Ratelimit-Retry: 20. Wildberries — единственный из трёх, кто отдаёт заголовки лимита: X-Ratelimit-Limit, -Remaining и -Reset приходят с каждым ответом, -Retry добавляется к 429.

Конверт ошибки самый подробный из трёх:

{"title":"Not Found","detail":"path not found","code":"NotFound","requestId":"0dcf08a519c89fe14c98a7c727fd116f","origin":"ag-gateway","status":404,"statusText":"not_found","timestamp":"2026-09-09T10:15:46.639Z"}

Поле origin различается: ag-api у ошибок сервиса, ag-gateway — у 404 по пути и у таймаута. requestId совпадает с X-Request-Id ответа.

Известные отличия от боя

Важно

  • suppliers-api.wildberries.ru — исторический адрес. Он указан в профиле сервиса как «что подменяет /wb», но реальные хосты методов в каталоге другие: marketplace-api, content-api, advert-api, seller-analytics-api, statistics-api, discounts-prices-api, feedbacks-api и ещё десяток. Какой хост подменяет конкретный метод, показывает X-APIStend-Upstream в его ответе.
  • Разные хосты в бою — разные лимиты и разные токены. В песочнице ведро одно на весь сервис, а токен один на все хосты. Код, разложенный по хостам правильно, на стенде работать будет; обратное неверно.
  • 29 методов отвечают 204 с пустым телом — там, где в спецификации успешный ответ описан без содержимого.
  • Больше половины ответов собрано по схеме (X-APIStend-Source: schema): форма из спецификации, значения выдуманы.
  • Тело ответа не зависит от запроса — включая значение {warehouseId} в пути. Два запроса на разные склады дают побайтово одинаковый ответ.

Данные, а не только форма

Стенд отвечает не абстрактными записями, а согласованным набором: все методы говорят про одни и те же артикулы, и цифры внутри товара сходятся между собой. Три вещи, из-за которых на этом можно считать экономику, а не только разбирать JSON.

Даты живут относительно сегодня. В документации Wildberries заказы датированы 4 марта 2022 года, воронка отвечает за период с июня 2023 по март 2024, тариф коробов действует до февраля 2024. Витрину продавца считают за последние 7, 30 или 90 дней — в это окно ничего из перечисленного не попадает ни при каком запросе. Поэтому даты сдвигаются: самая свежая приходится на сегодня, расстояния между ними сохраняются, а сроки действия уезжают в будущее.

Страница не обрезает ответ молча. Списки отдают до тысячи записей за раз — столько же, сколько разрешают боевые методы Wildberries. Карточная выдача settings.cursor.limit держится своего документированного потолка в сто карточек: карточка тяжёлая, и боевой сервис тысячу их не отдаёт. Прежний общий предел в двести записей выглядел как отсутствие данных — клиент просил тысячу цен, получал двести и считал, что на остальные карточки цены не заведены.

Каталог листается курсором. settings.cursor.nmID из ответа, возвращённый в следующий запрос, продолжает выдачу со следующей карточки; конец каталога — пустой список. Раньше курсор стоял на месте, и обход не заканчивался никогда.

Справочники пересекаются с каталогом. Комиссии приходят по одной строке на каждый предмет каталога, а не единственной записью «Оборудование зуботехническое» из документации: без пересечения ставку не к чему подобрать, и юнит-экономика не считается.

Заказы живут во времени. За последние девяносто дней песочница ведёт журнал: кто что заказал, что из этого выкупили, что отменили, что вернули. Из него отвечают /api/v1/supplier/orders, /api/v1/supplier/sales и лента заказов — поэтому у записей разные дни, разные товары и разные исходы. Доли исходов берутся из воронки самого товара: у карточки с 380 выкупами из 400 заказов и в журнале девять выкупов из десяти, и процент выкупа, посчитанный клиентом по журналу, сходится с тем, что отдаёт аналитика.

В продажи попадают только состоявшиеся сделки и возвраты: отменённый заказ продажей не становится. Возврат уносит выплату обратно — forPay со знаком минус и saleID, начинающийся с R, как в бою.

Период запроса влияет на ответ. dateFrom сужает выдачу, а не игнорируется: семь дней, тридцать и девяносто дают три разных ответа. Аналитика возвращает период, который спросили, а не интервал из документации, и цифры за него — сумма дней окна: квартал больше недели. .../products/history отдаёт ряд по дням окна с разными значениями — то, из чего строится график.

Без явного limit списки событий отдают всё запрошенное окно за раз, как боевая статистика Wildberries: клиент строит график за девяносто дней одним запросом, а не собирает его из страниц по двадцать записей.

Реклама сходится сама с собой. Список кампаний, статистика и разнесение расхода по карточкам говорят об одних и тех же кампаниях: advertId из /adv/v1/adverts — тот самый, по которому отвечает /adv/v3/fullstats. Клиент берёт идентификаторы из списка и просит по ним статистику; ответ про другие кампании он привязать не может, и расход у него уходит в никуда вместе с ДРР, кликами, CTR и CPC. Чужой идентификатор не выдумывается — статистики по нему просто нет, как и в бою.

Расход сходится на всех уровнях: сложили карточки — получили день площадки, сложили площадки — день кампании, сложили дни — итог в шапке. Показатели согласованы между собой: кликов не больше показов, CTR — их отношение, CPC — расход, делённый на клики.

Кампании покрывают весь каталог, а не первые двадцать карточек: у каждой свои двадцать пять артикулов, свой период и свой бюджет. Завершённая кампания не тратит после даты окончания — график расхода у неё обрывается там, где должен. Без beginDate и endDate статистика отдаёт последнюю неделю: у боевого метода эти параметры обязательны.

Вопрос про карточку получает ответ про неё. nmID, nmIDs, filterNmID, imtID, артикул продавца, штрихкод и поисковая строка с артикулом внутри — всё это адресует конкретный товар, и ответ приходит про него, а не первой страницей каталога. Курсор settings.cursor.nmID при этом остаётся курсором: он говорит «продолжи с этой карточки», а не «покажи только её».

У каждой карточки есть всё. Заказы, выкупы, возвраты, воронка, история по дням, кампания с расходом, комиссия по предмету, остаток — по любому артикулу каталога, а не по первым двадцати. Выгрузка заказов сходится с аналитикой: сложив записи /api/v1/supplier/orders по товару за период, получите то же число, что стоит в orderCount воронки за тот же период.

У оценки товара — два масштаба, и оба сходятся, но каждый со своим. POST /api/analytics/v2/item-rating отдаёт рейтинг и отзывы дважды: по каждой карточке (items[].feedbackRating/feedbackCount/пятизвёздочные- однозвёздочные) и по аккаунту целиком (sellerRating, feedbackIncrease). У аккаунтного свода в свою очередь два числа с разным охватом — ровно так же, как в боевой спецификации: feedbackIncrease.total (и total внутри каждой звезды) — это всё время существования товаров, то же число, что отдаёт GET /api/common/v1/rating; feedbackIncrease.current (и current внутри каждой звезды) — это прирост за запрошенный currentPeriod, и вот он ровно складывается из feedbackCount.current/звёзд всех карточек каталога: сложите их по всем страницам — получите feedbackIncrease.current день в день. Читать .total, ожидая, что он сойдётся с суммой по карточкам за неделю или месяц, не стоит — это не то же число: он больше настолько, насколько отзывы старше запрошенного периода.

Запись сохраняется

Четыре метода не просто отвечают успехом, а меняют то, что видит следующий запрос той же песочницы, — как в бою:

  • POST /content/v2/cards/update — название, описание, характеристики. Проверяются nmID/vendorCode/sizes (обязательны), длина названия (60 символов) и описания (5000), и характеристики — по небольшому справочнику песочницы (14177449 «Цвет» и 14177450 «Состав» — настоящие ID из спецификации; полного каталога характеристик по каждому из тысяч предметов WB стенд не ведёт). GET /content/v2/object/charcs/{subjectId} отдаёт этот же справочник — только характеристики запрошенного предмета, с настоящими именами («Цвет», а не название товара), теми же ID, что примет cards/update.
  • POST /api/v2/upload/task — цена и скидка. Отвечает id загрузки сразу же обработанным (status: 3 в GET /api/v2/history/tasks) — песочница не моделирует очередь обработки.
  • POST /content/v3/media/save и POST /content/v3/media/file — фото. Ссылки сохраняются как есть; у файла, загруженного вторым методом, реального содержимого нет — только адрес, детерминированный по артикулу и номеру.

GET/POST /content/v2/get/cards/list и GET/POST /api/v2/list/goods/filter отдают уже сохранённое. Изменения приватны для ключа, которым записаны (разные песочницы не видят чужих правок), и переживают перезапуск стенда — до POST /api/sandbox/reset, который их и стирает.