Интеграция с WB API: заметки для разработчиков
Как бэкенд «Оптимы» обращается к Wildberries Seller API: домены, категории токена по модулям, лимиты, повторы и обработка 429. Архитектурный обзор интеграции — Архитектура: интеграция с WB.
Весь код интеграции — backend/src/modules/wb-api. Фичевые модули не ходят в WB напрямую:
только через WbApiClient.request({ scope, path, apiKey, accountId, … }). API-ключ
кабинета хранится зашифрованным (AES-256-GCM, ADR-0005)
и расшифровывается непосредственно перед запросом.
Домены (scope)
Каждая категория WB API — отдельный домен. Таблица WB_API_BASE_URLS в
backend/src/modules/wb-api/wb-api-scope.ts; источник — метод /ping в
wildberries-api/01-general.yaml.
scope | Категория токена WB | Production | Sandbox |
|---|---|---|---|
common | Тарифы, Новости, Информация о продавце | https://common-api.wildberries.ru | — |
content | Контент | https://content-api.wildberries.ru | https://content-api-sandbox.wildberries.ru |
analytics | Аналитика | https://seller-analytics-api.wildberries.ru | — |
prices | Цены и скидки | https://discounts-prices-api.wildberries.ru | https://discounts-prices-api-sandbox.wildberries.ru |
marketplace | Маркетплейс | https://marketplace-api.wildberries.ru | — |
statistics | Статистика | https://statistics-api.wildberries.ru | https://statistics-api-sandbox.wildberries.ru |
advert | Продвижение | https://advert-api.wildberries.ru | https://advert-api-sandbox.wildberries.ru |
feedbacks | Вопросы и отзывы | https://feedbacks-api.wildberries.ru | https://feedbacks-api-sandbox.wildberries.ru |
buyer-chat | Чат с покупателями | https://buyer-chat-api.wildberries.ru | — |
supplies | Поставки | https://supplies-api.wildberries.ru | — |
returns | Возвраты покупателями | https://returns-api.wildberries.ru | — |
documents | Документы | https://documents-api.wildberries.ru | — |
finance | Финансы | https://finance-api.wildberries.ru | — |
user-management | Управление пользователями продавца | https://user-management-api.wildberries.ru | — |
Sandbox включается переменной WB_API_USE_SANDBOX=true (нужен токен «Тестовый контур»).
Для категорий без sandbox клиент бросает явную ошибку, а не уходит молча в production.
Какие категории токена нужны модулям
Таблица собрана по фактическим вызовам WbApiClient в коде (константы *_SCOPE и *_PATH
модулей). Категории marketplace, buyer-chat, returns, documents и user-management
в клиенте описаны, но сейчас ни одним модулем не используются.
| Модуль «Оптимы» | Модуль ТЗ | scope | Методы WB | Запись в WB |
|---|---|---|---|---|
Кабинеты (wb-accounts) | Общие | common | GET /ping — проверка ключа | — |
Каталог (catalog) | Общие | content, prices | POST /content/v2/get/cards/list, GET /api/v2/list/goods/filter | — |
Оцифровка (digitization) | 5.1 | statistics, finance | GET /api/v1/supplier/orders, GET /api/v1/supplier/sales, POST /api/finance/v1/sales-reports/detailed | — |
Цены и скидки (pricing) | 5.2 | prices | POST /api/v2/upload/task | да |
Репрайсер (repricer) | 5.3 | prices | POST /api/v2/upload/task | да |
Автобиддер (autobidder) | 5.4 | advert | GET /adv/v1/promotion/count, /api/advert/v2/adverts, /adv/v3/fullstats, PATCH /api/advert/v1/bids, GET /adv/v0/pause | да |
ИИ-агент (ai-agent) | 5.10 | advert (через сервисы автобиддера) | ставки, бюджеты, пауза кампаний | да |
Автоответы (autoreply) | 5.5 | feedbacks | GET /api/v1/feedbacks, GET /api/v1/questions, POST /api/v1/feedbacks/answer, PATCH /api/v1/questions | да |
РНП (rnp) | 5.6 | analytics; также advert и finance через сервисы автобиддера и оцифровки | POST /api/analytics/v3/sales-funnel/products/history, fullstats, отчёт реализации | — |
Бронировщик (booking) | 5.8 | common, supplies | GET /api/tariffs/v1/acceptance/coefficients, GET /api/v1/warehouses | — |
Товарный учёт (inventory) | 5.11 | analytics | /api/v1/warehouse_remains (создание задачи → статус → скачивание) | — |
A/B-тесты (ab-test) | 5.14 | content | POST /content/v3/media/file — загрузка фото варианта | да |
База знаний (knowledge-base) | 5.15 | common | GET /api/communications/v2/news | — |
Модули без обращений к WB: бухгалтерия (считает по данным оцифровки), ИИ-помощник, генерация контента, досудебные претензии, уведомления.
Практический вывод. Чтобы работали все модули, токен кабинета должен включать категории: Контент, Аналитика, Цены и скидки, Статистика, Продвижение, Вопросы и отзывы, Поставки, Финансы, а также Тарифы, Новости, Информация о продавце. Для модулей, которые пишут в WB (колонка «Запись в WB»), токен должен быть выпущен с правом записи.
Проверка ключа POST /wb-accounts/:id/check вызывает только GET /ping на
common-api. Она подтверждает, что ключ действителен, но не проверяет набор категорий:
нехватка категории проявится позже, ответом 401/403 от WB в конкретном модуле
(клиенту API вернётся WB_AUTH_FAILED).
Лимиты запросов
Лимиты WB действуют «на аккаунт продавца». «Оптима» соблюдает их сама, до отправки
запроса: распределённый token-bucket в Redis (WbRateLimiter,
ADR-0041). Ключ бакета —
wb:rl:v2:<accountId>:<scope>:<path>, то есть лимит считается отдельно для каждого
кабинета и метода и общий для всех реплик и воркеров.
Реестр — backend/src/modules/wb-api/wb-rate-limits.ts. Сначала ищется точное
переопределение scope:path, иначе берётся значение по умолчанию для scope.
По умолчанию для scope (запросов за окно):
scope | Лимит |
|---|---|
common | 3 / 30 с |
content, marketplace, advert, feedbacks | 100 / 60 с |
analytics, prices, statistics, buyer-chat, supplies, returns, documents, finance | 60 / 60 с |
user-management | 5 / 1 с |
Переопределения для методов:
Метод (scope:path) | Скорость | Всплеск |
|---|---|---|
*:/ping (каждый scope отдельно) | 3 / 30 с | — |
common:/api/v1/seller-info | 1 / 60 с | — |
common:/api/communications/v2/news | 1 / 60 с | — |
common:/api/tariffs/v1/acceptance/coefficients | 6 / 60 с | — |
supplies:/api/v1/warehouses | 6 / 60 с | — |
statistics:/api/v1/supplier/orders | 1 / 60 с | 10 |
statistics:/api/v1/supplier/sales | 1 / 60 с | — |
finance:/api/finance/v1/sales-reports/detailed | 1 / 60 с | — |
analytics:/api/v1/warehouse_remains (создание задачи) | 1 / 60 с | 5 |
analytics:…/warehouse_remains/tasks/{task_id}/status | 1 / 5 с | — |
analytics:…/warehouse_remains/tasks/{task_id}/download | 1 / 60 с | — |
analytics:/api/analytics/v3/sales-funnel/products/history | 3 / 60 с | — |
prices:/api/v2/upload/task | 10 / 6 с | — |
advert:/adv/v3/fullstats | 1 / 20 с | — |
«Всплеск» — ёмкость корзины: столько запросов можно выпустить залпом из полной корзины,
дальше действует установившаяся скорость. Пути задачных отчётов канонизируются
({task_id} вместо uuid), чтобы все задачи кабинета делили один бакет.
Текущее состояние бакетов кабинета отдаёт GET /wb-accounts/:id/quota (только чтение).
Сверка с заголовками WB
На каждом ответе WB (любого статуса) клиент читает X-Ratelimit-Remaining,
X-Ratelimit-Limit, X-Ratelimit-Reset и X-Ratelimit-Retry и только сужает локальный
бакет: при Remaining: 0 корзина обнуляется до сброса окна WB. Расхождение Limit с
реестром пишется в лог на уровне verbose — как материал для ручной правки
wb-rate-limits.ts (ADR-0066).
Повторы и поведение на 429
Два уровня повторов: внутри одного HTTP-запроса (WbApiClient, wb-retry.ts) и на
уровне фоновой задачи BullMQ.
HTTP-уровень (WB_API_RETRY_ATTEMPTS, по умолчанию 3 попытки, включая первую):
| Ошибка | Повтор | Пауза |
|---|---|---|
| 429 | да | min(max(Retry-After, восполнение одного токена, экспонента), потолок) |
| 5xx, сетевой сбой, таймаут | да | экспонента WB_API_RETRY_BASE_MS × 2^(n−1) + jitter |
| таймаут чтения тела с явно заданным бюджетом | нет | — |
| 401, 403, 404 | нет | — |
- Пауза на 429 никогда не короче восполнения одного токена бакета
(
ceil(интервал / токены): 60 с для фидов продаж, 600 мс для цен). КороткийRetry-Afterот WB поднимается до этого значения (ADR-0048). - После реального 429 от WB бакет штрафуется: корзина осушается, и до момента
notBeforeтокены не выдаются никому, включая другие воркеры. Штраф ставится и на последней попытке. - Потолок ожидания —
max(WB_API_RATE_LIMIT_MAX_WAIT_MS, N × окно + 5 с), гдеN = 2для лимитов 1 запрос/окно, иначе 1. Он общий для ожидания токена и паузы ретрая. Если ожидание токена превышает потолок, клиент сразу получаетWbApiRateLimitedErrorсRetry-Afterбез похода в WB. Для HTTP-клиента «Оптимы» это ответ 429TOO_MANY_REQUESTSсdetails.retryAfterSeconds.
Уровень задач.
- Перенос вместо сна (ADR-0051). В длинных
синках (
digitization-sync,rnp-ads-sync,rnp-finance-sync,rnp-sections-sync,inventory-sync,autobidder-sync) ожидание токена дольше 5 секунд не «спит» в воркере: задача переносится вdelayedи освобождает слот, а попытка не расходуется. Короткие очереди (pricing-bulk,booking-slot-monitor) не оборачиваются. - Минутная лестница у пользовательских импортов (
import-user-feeds,import-user-report,autobidder-sync-user): 5 попыток, экспонента от 60 с (60 → 120 → 240 → 480 с). Ошибки, которые повтором не лечатся (401/403/404), завершают задачу сразу (UnrecoverableError). - Gate кабинета (ADR-0057). По одному кабинету
одновременно работает одна WB-тяжёлая задача (lease
wb:gate:<accountId>в Redis, TTL 90 с, heartbeat 30 с). Пользовательские задачи приоритетнее плановых. Плановая задача, не дождавшаяся gate, завершается сskipped: account-busy, и кабинет подхватит следующий тик. - Фаза ожидания видна клиенту в поле
progress.phaseстатуса задачи (waiting-account,rate-limited,retrying) — см. Обзор API, раздел «Длительные операции».
Предыстория решений — ADR-0006 (исходная
политика лимитов и повторов) и ADR-0040
(параллелизм sync-очередей, SYNC_QUEUE_CONCURRENCY).
Как добавить вызов нового метода WB
- Найдите метод в базе знаний (см. ниже): домен, путь, лимит «на один аккаунт продавца».
- Если лимит метода отличается от значения по умолчанию для его scope, добавьте
переопределение в
WB_ENDPOINT_RATE_LIMITS(wb-rate-limits.ts) с комментарием-источником. - Вызывайте метод через
WbApiClient.requestсaccountIdкабинета: без него лимит считается на глобальном ключе_global. - Если метод нужен длинному синку, оберните обработку задачи в
WbRateLimitRescheduleService.runи, при необходимости, подключите gate кабинета. - Обновите таблицу «Какие категории токена нужны модулям» на этой странице.
База знаний WB API
-
wildberries-api/(в корне монорепо) — исходные OpenAPI YAML WB по разделам (01-general.yaml…13-finances.yaml), сводки разделов вknowledge/*.mdи машинные индексыindexes/(methods.jsonl,documents.jsonl,auth.jsonl,domains.jsonl). -
Навык
wb-api-knowledge(.claude/skills/wb-api-knowledge) — поиск по методам, доменам, авторизации и лимитам для AI-агентов и разработчиков:cd .claude/skills/wb-api-knowledgepython3 scripts/search_knowledge.py "<запрос>" [--kind documents] [--domain <name>]Нужен Python 3. Приоритет источников:
indexes/methods.jsonl→documents.jsonl→auth.jsonl→domains.jsonl→knowledge/*.md→ исходные YAML.
Связанные страницы
- Обзор API
- Переменные окружения —
WB_API_*,SYNC_QUEUE_CONCURRENCY - Архитектура: интеграция с WB
- Архитектура: фоновые задачи
- Кабинеты WB — пользовательская инструкция по подключению кабинета