API: загрузка закупочных цен из вашей программы

Обновлено · Команда «В плюсе»

Закупочные цены — единственные данные, которые маркетплейс о вас не знает: их вводите вы. Если закупки уже живут в вашей учётной системе — МойСклад, 1С, таблица со скриптом, — присылать их к нам можно программой, а не выгружать файл руками каждую неделю.

Для этого есть API: вы выпускаете ключ в кабинете, ваша программа шлёт с ним запросы. Всё, что делает API, вы можете сделать и руками в разделе «Цены» — API просто избавляет от ручной работы.

Кому это нужно

Только тем, у кого закупочные цены уже ведутся в другой программе. Если вы заводите цены руками или загружаете файл — API вам не нужен, ничего нового он не покажет.

API входит в подписку, а не в бесплатный доступ

Ключ можно выпустить и на демо, и на подписке. На бесплатном доступе запросы к API отвечают 402: это единственная часть сервиса, которая в него не входит. Всё остальное — на тех же условиях, что у всех.

Как выпустить ключ

  1. 1

    Профиль → «Ключи API» → «Настроить»

    Или сразу по адресу «Ключи API».
  2. 2

    Назовите ключ и нажмите «Выпустить»

    Название — по программе, которая будет им пользоваться: «МойСклад», «1С». Когда ключей несколько, только по названию и понятно, какой можно отозвать.
  3. 3

    Скопируйте ключ сразу

    Мы храним не сам ключ, а его отпечаток, поэтому показать значение второй раз не сможем. Потеряли — выпустите новый, а старый отзовите.

Ключ — это доступ к вашим данным

Ключ работает вместо логина и пароля: кто им владеет, тот может читать и менять ваши закупочные цены. Не выкладывайте его в переписку, в публичный репозиторий и в скриншоты настроек. Если ключ мог утечь — отзовите его в кабинете, это действует сразу же.

Как устроен запрос

Адрес — https://sellervpluse.ru/api/v1/…, ключ передаётся заголовком Authorization. Тело запросов и ответов — JSON.

Проверка ключа — с неё стоит начать
curl https://sellervpluse.ru/api/v1/ping \
  -H "Authorization: Bearer ВАШ_КЛЮЧ"
Ответ
{
  "ok": true,
  "account": { "email": "you@example.com" },
  "key": { "name": "МойСклад" }
}

Если вместо этого пришла ошибка — дальше идти незачем: сначала разберитесь с ключом, иначе ошибку загрузки цен не отличить от ошибки доступа.

Загрузка закупочных цен

POST /api/v1/prices — присылаете список артикулов с ценами и дату, с которой они действуют.

Запрос
curl -X POST https://sellervpluse.ru/api/v1/prices \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "validFrom": "2026-08-01",
    "prices": [
      { "article": "SHIRT-RED-M",  "price": 450 },
      { "article": "SHIRT-BLUE-L", "price": 480.50 }
    ]
  }'
Ответ
{
  "created":    2,
  "updated":    0,
  "unchanged":  0,
  "duplicates": 0,
  "errors":     []
}
ПолеЧто означает
validFromДата в формате ГГГГ-ММ-ДД, с которой действуют присланные цены. Необязательное поле, но почти всегда его надо указывать — см. следующий раздел. Одна дата на весь запрос.
prices[].articleВаш артикул продавца — тот, под которым товар приходит в заказах.
prices[].priceЗакупочная цена за штуку, в рублях. Число, а не строка. Ноль не принимается: «ноль» — это не цена, а незаполненное поле.
created / updatedСколько цен добавлено и сколько исправлено.
unchangedСколько артикулов пропущено: цена по ним уже такая же. Это нормальный результат ежедневной заливки всего прайса — записывается только то, что изменилось.
errorsСтроки, которые не удалось принять: артикул и причина. Остальные цены при этом записаны.

За один запрос принимается до 50 000 цен, а тело запроса — до 10 МБ (прайс на 50 000 позиций весит около 2 МБ, так что упереться в мегабайты раньше, чем в строки, трудно). Запись целиком либо проходит, либо не проходит: половины не бывает, поэтому при ошибке достаточно повторить тот же запрос.

Главное про дату «действует с»

Не оставляйте validFrom пустым, если цены нужны к прошлым продажам

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

Цены у нас хранятся с историей: у каждой есть период действия, и к продаже применяется та, что действовала в день продажи. Поэтому дата — это не формальность, а то, к каким продажам присланные цифры относятся.

Если вы поднимаете цены с сегодняшнего дня — поле можно не заполнять. Если загружаете закупки задним числом (первый раз или чтобы закрыть пробелы) — укажите дату, с которой они действовали на самом деле.

Каких цен не хватает

GET /api/v1/prices/missing отвечает на вопрос «по каким товарам вы продаёте, а закупки не знаете». Это тот же список, что в кабинете по кнопке «Товары без себестоимости».

Запрос и ответ
curl "https://sellervpluse.ru/api/v1/prices/missing" \
  -H "Authorization: Bearer ВАШ_КЛЮЧ"

{
  "articles": [
    {
      "article":      "SHIRT-RED-M",
      "orders":       12,
      "firstOrderAt": "2026-07-01T00:00:00.000Z",
      "lastOrderAt":  "2026-08-10T00:00:00.000Z",
      "costArticle":  null
    }
  ],
  "total": 1,
  "windowDays": 90
}

firstOrderAt — дата самой ранней продажи, которая осталась без цены. Именно её (самую раннюю по всей пачке) и стоит поставить в validFrom, когда вы дозаливаете недостающие цены: иначе цена «с сегодня» эти продажи не закроет и товар из списка не исчезнет.

Список считается за последние 90 дней — столько же, сколько мы храним подробности заказов. Пустой ответ означает «за 90 дней всё заполнено».

costArticle: куда заводить цену у товаров Авито

У Авито в поле article стоит номер объявления: своего артикула площадка не отдаёт вовсе. Если вы связали объявления со своими артикулами в кабинете (кнопка «Артикулы Авито» в разделе «Цены»), в ответе придёт ещё и costArticle — тот самый ваш артикул.

Цену заводите на costArticle, когда он не пуст, и на article, когда там null. Иначе у товара окажется две закупочные цены: одна из вашего прайса, другая заведённая скриптом на номер объявления, — и правка прайса на вторую влиять перестанет. У трёх других площадок поле всегда null: артикул продавца там приходит сам.

Выгрузка цен

GET /api/v1/prices отдаёт то, что у нас записано, — например, чтобы сверить с прайсом в своей системе.

Запрос и ответ
curl "https://sellervpluse.ru/api/v1/prices?limit=500&page=1" \
  -H "Authorization: Bearer ВАШ_КЛЮЧ"

{
  "prices": [
    {
      "article":    "SHIRT-RED-M",
      "price":      "450.00",
      "validFrom":  "2026-08-01T00:00:00.000Z",
      "validUntil": null
    }
  ],
  "total": 1, "page": 1, "pageCount": 1, "limit": 500
}
ПараметрЧто делает
articleПоиск по части артикула.
history=1Добавить прошлые цены. По умолчанию отдаются только действующие (validUntil: null).
limit, pageСтраница: по умолчанию 500 строк, максимум 1000. Сколько всего страниц — в поле pageCount. Вглубь листание идёт до миллиона строк: номер страницы за этой границей отдаёт последнюю доступную, а не ошибку.

Ошибки и ограничения

У ошибки всегда есть HTTP-код, текст в поле error и машинный код в поле code. Ветвиться в своём скрипте нужно по code: текст мы можем переформулировать.

КодЧто случилосьЧто делать
401Ключ не передан, недействителен или отозван.Проверьте заголовок; при необходимости выпустите новый ключ.
402Демо-доступ закончился, подписки нет — либо доступ бесплатный.Оплатите подписку: в бесплатный доступ API не входит.
400Тело запроса не прошло проверку.Подробности — в поле details.
413Тело запроса больше 10 МБ. В поле code — BODY_TOO_LARGE.Разбейте загрузку на части — например, по 10 000 цен, — и присылайте их по очереди с одной и той же датой validFrom.
408Запрос к данным не уложился в отведённое время и был прерван. В поле code — DB_TIMEOUT.Запросите период короче или один магазин за раз: потолок стоит на один запрос, а не на их число.
429Слишком много запросов. В поле code — RATE_LIMIT, если исчерпан лимит этого ключа, и RATE_LIMIT_ACCOUNT, если общий лимит аккаунта.Подождите столько секунд, сколько указано в заголовке Retry-After, и повторите. При RATE_LIMIT_ACCOUNT смотрите и на расписание остальных своих интеграций: квоту израсходовали они.
500Ошибка на нашей стороне.При загрузке цен это означает, что не записалось ничего, — просто повторите запрос.

Сколько запросов можно слать

  • Чтение (ping, выгрузка цен, список без себестоимости) — 120 запросов в минуту на ключ, 240 в минуту на аккаунт.
  • Загрузка цен — 60 запросов в час на ключ, 120 в час на аккаунт.

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

Регулярной заливке прайса — хоть раз в час — этого хватает с запасом: весь прайс уезжает одним запросом, разбивать его по товарам не нужно и вредно.

Как это обычно настраивают

  1. 1

    Первая заливка — задним числом

    Спросите /api/v1/prices/missing, возьмите самую раннюю firstOrderAt и загрузите весь прайс с этой датой в validFrom. Так закроются уже накопленные продажи.
  2. 2

    Дальше — по расписанию

    Раз в сутки (или как часто меняются закупки) шлите весь прайс без validFrom. Записываться будет только изменившееся: в ответе это видно по created и updated.
  3. 3

    Проверяйте, что пробелов не осталось

    Тем же /api/v1/prices/missing: пустой список означает, что прибыль считается по всем продажам.

Если что-то не сходится — загляните в раздел «Цены»: там видно то же самое глазами. А как история цен влияет на прибыль, разобрано в статье «Себестоимость и история цен».

Читайте также

Посмотрите на своих цифрах

Прикиньте прибыль по своему товару прямо на калькуляторе — без регистрации и карты.