Аутентификация
Каждый вызов Wildberries Seller API требует bearer JWT в заголовке Authorization. Клиенты сами подставляют заголовок; вы передаёте только токен.
Откуда берётся токен
Токены выпускаются в кабинете продавца:
- seller.wildberries.ru → раздел Интеграции по API.
- + Создать токен → вкладка Для интеграции вручную → выберите тип токена: персональный, базовый или тестовый для песочницы.
- Заполните название, выберите категории методов (Контент, Маркетплейс, Аналитика, …) и уровень доступа — Чтение и запись или Только чтение.
- Создать → Скопировать и закрыть. Токен показывают один раз — сохраните его сразу.
Каждой выбранной категории примерно соответствует один или несколько под-модулей в клиенте. Если пришёл 403 — токен валиден, но прав не хватает; перевыпустите с нужной категорией.
Какой тип токена выбрать:
- Персональный — для собственных программ и on-premise систем (включая локальные версии 1С). Даёт доступ к чувствительным данным, поэтому его нельзя передавать третьим лицам и использовать в облачных сервисах.
- Базовый — доступ к ограниченному набору данных. Подходит для проверки интеграции на реальных данных и для случаев, когда персональный использовать нельзя.
- Тестовый — работает только с песочницей WB API и сгенерированными тестовыми данными; доступа к реальным данным продавца нет.
- Сервисный — создаётся для конкретного облачного сервиса из каталога «Решения для бизнеса»; категории и уровни доступа заполняются автоматически.
Любой токен живёт 180 дней с момента создания, после чего нужно выпустить новый. Проверить валидность токена и его категории можно, декодировав JWT — это строка по RFC 7519. Не вставляйте токен в онлайн-декодеры: так его может перехватить кто угодно.
Обёртки SecretString
Получив токен, не носите его по коду как обычную строку. Каждый клиент оборачивает значение в языко-специфичный «секретный» тип — он маскирует токен в логах, print-выводе, отладчике и дампах ошибок, пока вы явно не запросите значение.
| Язык | Обёртка | Сеттер | Маскируется в | Явное значение |
|---|---|---|---|---|
| Python | pydantic.SecretStr | Configuration(access_token=…) | print(cfg.access_token) → ********** | .get_secret_value() |
| TypeScript | встроенный класс SecretString | Configuration.setAccessToken(…) | console.log(new SecretString("…")) → <REDACTED> | .exposeSecret() |
| Go | secrecy.SecretString | Configuration.SetAccessToken(…) | fmt.Printf("%v", cfg.AccessToken) → <!SECRET_LEAKED!> | .ExposeSecret() |
| Java | SecretString в каждом под-пакете | ApiClient.setAccessToken(String) | System.out.println(s) → <REDACTED> | .exposeSecret() |
| PHP | SecretString в каждом под-пространстве | Configuration::setAccessToken(string) | var_dump($config) → '<REDACTED>' | $config->getAccessToken() |
| C# | SecretString в каждом пространстве имён | Configuration.SetAccessToken(…) | Console.WriteLine(new SecretString("…")) → <REDACTED> | .ExposeSecret() |
| OneScript | класс СекретнаяСтрока | Конфигурация.УстановитьТокен(…) | Сообщить(Настройки.Токен()) → СекретнаяСтрока | .Раскрыть() |
| Rust | SecretString в каждом модуле | Configuration::set_access_token(…) | println!("{s:?}") / {} → <REDACTED> | .expose_secret() |
Зачем это нужно
Реальные ситуации, ради которых это сделано:
- Логгер-middleware, который в трейсе ошибки дампит всю конфигурацию запроса.
print(config), оставленный в коде после отладки.- Исключения, сериализованные в Sentry / трекер вместе с полным контекстом HTTP-клиента.
- Отладчик IDE, показывающий поля объекта на демо-встрече по шаринг-скрину.
Обёртка превращает каждый из этих сценариев из утечки токена в безобидную метку <REDACTED>. Цена — одна строка кода в точке ввода.
Как это выглядит на практике
from wb_api_client.items import Configuration
cfg = Configuration(access_token="eyJhbGciOi...")
print(cfg.access_token) # SecretStr('**********')
print(cfg.access_token.get_secret_value()) # eyJhbGciOi... (по запросу)import { Configuration } from "@valeryverkhoturov/wb-api-client/items";
const cfg = new Configuration({});
cfg.setAccessToken("eyJhbGciOi...");
console.log(cfg.accessToken); // SecretString { <REDACTED> }
console.log(cfg.accessToken.exposeSecret()); // eyJhbGciOi... (по запросу)import wbitems "github.com/ValeryVerkhoturov/wb-api-client-go/items"
cfg := wbitems.NewConfiguration()
cfg.SetAccessToken("eyJhbGciOi...")
fmt.Printf("%v\n", cfg.AccessToken) // <!SECRET_LEAKED!>
fmt.Println(cfg.AccessToken.ExposeSecret()) // eyJhbGciOi... (по запросу)import io.github.valeryverkhoturov.wbapi.items.SecretString;
SecretString s = new SecretString("eyJhbGciOi...");
System.out.println(s); // <REDACTED>
System.out.println(s.exposeSecret()); // eyJhbGciOi... (по запросу)use ValeryVerkhoturov\WbApiClient\Items\SecretString;
$s = new SecretString('eyJhbGciOi...');
var_dump($s); // object(...) { ['value']=> '<REDACTED>' }
echo $s->exposeSecret(); // eyJhbGciOi... (по запросу)С = Новый СекретнаяСтрока("eyJhbGciOi...");
Сообщить(С); // СекретнаяСтрока
Сообщить(С.Раскрыть()); // eyJhbGciOi... (по запросу)var s = new SecretString("eyJhbGciOi...");
Console.WriteLine($"{s}"); // <REDACTED>
Console.WriteLine(s.ExposeSecret()); // eyJhbGciOi... (по запросу)use wb_api_client::items::apis::configuration::SecretString;
let s = SecretString::new("eyJhbGciOi...");
println!("{s:?}"); // <REDACTED>
println!("{}", s.expose_secret()); // eyJhbGciOi... (по запросу)Один токен на несколько под-модулей
Если в процессе вы используете сразу несколько под-модулей, у каждого — свой Configuration / ApiClient. Так задумано: openapi-generator создаёт полностью изолированные SDK на каждую спецификацию. Переиспользуйте строку токена, но конструируйте конфиг на каждый модуль.
from wb_api_client.items import Configuration as ItemsCfg, ApiClient as ItemsClient
from wb_api_client.orders_fbs import Configuration as OrdCfg, ApiClient as OrdClient
TOKEN = "<ваш JWT WB>"
items_api = ItemsClient(ItemsCfg(access_token=TOKEN))
orders_api = OrdClient(OrdCfg(access_token=TOKEN))import { Configuration as ItemsCfg } from "@valeryverkhoturov/wb-api-client/items";
import { Configuration as OrdCfg } from "@valeryverkhoturov/wb-api-client/orders_fbs";
const TOKEN = "<ваш JWT WB>";
const itemsCfg = new ItemsCfg({}); itemsCfg.setAccessToken(TOKEN);
const ordCfg = new OrdCfg({}); ordCfg.setAccessToken(TOKEN);Ротация токенов
Токены WB не ротируются сами и живут максимум 180 дней — их нужно заменять вручную. Хорошая практика:
- Держите токен в секрет-менеджере (SSM, Vault, GitHub Actions secret) — не в исходниках.
- Читайте в переменную окружения при старте процесса и конструируйте конфиг один раз.
- На ротации: убейте процесс (или пул соединений) и запустите заново с новым токеном. Клиент кэширует токен на уровне экземпляра Configuration.
Типичные ошибки авторизации
| Ответ | Значение |
|---|---|
401 Unauthorized — token expired | Срок токена истёк; выпустите новый |
401 Unauthorized — invalid signature | Неверный формат заголовка Authorization или токен от другой среды (sandbox / prod) |
403 Forbidden — no access to resource | Токен валиден, прав не хватает — перевыпустите с правильной галочкой |
429 Too Many Requests | Rate-limit; сам токен в порядке |
Ретраи и работа с ошибками — в руководстве по обработке ошибок.
