Методы API. Товары и остатки

Методы API для товаров и остатков — команды, которыми связка Альбато без панели магазина ищет и выгружает товары, создаёт и меняет карточки, корректирует остатки и читает историю движений. Это вторая часть справочника, для методов нужны права группы «Товары и остатки». Ниже — правила запросов, методы с примерами и ограничения токена.

Перед началом

Отправляйте запросы на адрес https://домен-магазина/api/v2/… с API-токеном в заголовке X-Service-Token. API-токен — секретный ключ, по которому магазин узнаёт связку и проверяет её права. Токен выпускают в разделе «Подключения» на вкладке «Альбато» и отмечают флажками нужные права — подробнее в статье «API-токены». Для методов этой статьи нужны права группы «Товары и остатки».

Тело запроса передаётся в формате JSON (текст из пар «поле — значение») с заголовком Content-Type: application/json. Магазин определяется по токену, storeId передавать не нужно.

Если товара с указанным ID нет в магазине токена, в том числе если он удалён, API отвечает кодом 403 resource does not belong to service token store, а не 404.

📘 Общие правила запросов и коды ответов описаны в статье «Методы API. Заказы и клиенты». Об изменениях в каталоге магазин сообщает вебхуками: вебхук — автоматический запрос, который магазин отправляет на адрес из настроек, когда происходит событие. Поля событий описаны в статье «События вебхуков».

Связка — сценарий в Альбато. Заказы и клиенты описаны в первой части справочника «Методы API. Заказы и клиенты», исполнители и записи на услуги — в третьей, «Методы API. Исполнители и записи».

Товары

Получить товар или список товаров

GET /api/v2/goods

Права: «Товары и остатки» → «Чтение».

С параметром id метод вернёт один товар объектом без обёртки. Без id придёт список: {"count": …, "rows": […]}, где count — число товаров по фильтрам без учёта страниц.

  • id — ID одного товара. Остальные фильтры не учитываются.
  • ids — до 200 ID через запятую, например 12,15,40. Ответ — список в том же порядке.
  • otherId — точное совпадение кода товара во внешней системе, например из 1С.
  • search — часть названия или артикула, без учёта регистра.
  • modelId — ID категории. Товары вложенных категорий не попадают.
  • parentGoodId — варианты указанного товара.
  • type — тип: physical — физический товар, digital — цифровой, service — услуга, category — карточка-категория.
  • excludeVariants — true, чтобы не показывать варианты товаров.
  • limit, offset — размер страницы и сдвиг от начала. Сортировка — по возрастанию id.

⚠️ Важно: без limit метод вернёт весь каталог одним ответом. Всегда передавайте limit, например 50, и перебирайте страницы через offset.

Пример — найти товар по коду из учётной системы:

GET https://myshop.ru/api/v2/goods?otherId=1C-000123&limit=1
X-Service-Token: ваш_токен
{
  "count": 1,
  "rows": [
    {
      "id": 42,
      "type": "physical",
      "caption": "Футболка базовая",
      "article": "TS-001",
      "otherId": "1C-000123",
      "price": 1990.00,
      "oldPrice": 2490.00,
      "modelId": 7,
      "parentGoodId": null,
      "hasVariants": false,
      "onModeration": false,
      "stopListId": null,
      "physical": {
        "trackStock": true,
        "stockQty": 12,
        "lowStockThreshold": 3
      }
    }
  ]
}

Если товар не найден, придёт {"count": 0, "rows": []}. В ответе много служебных полей, для связок обычно нужны эти:

  • caption, article, otherId — название, артикул и код во внешней системе. Артикул может повторяться, otherId в магазине уникален;
  • price, oldPrice — цена и старая цена;
  • onModeration — true, если товар скрыт с витрины; stopListId не равен null, если товар в стоп-листе;
  • physical.stockQty — остаток, доступный к продаже: резерв оформленных заказов уже вычтен. При physical.trackStock = false остаток не учитывается;
  • hasVariants — у товара есть варианты. Остатки таких товаров ведутся по вариантам: запросите их с параметром parentGoodId.

Получить все товары магазина

GET /api/v2/goods/all

Права: «Товары и остатки» → «Чтение».

Возвращает все товары магазина вместе с вариантами одним ответом {"count": …, "rows": […]}. Параметров нет. В строках только основные поля товара: остатков (physical), фото и признака стоп-листа здесь нет. Для большого каталога удобнее GET /api/v2/goods с limit.

Создать товар

POST /api/v2/goods

Права: «Товары и остатки» → «Создание товаров и корректировка остатков».

  • type — тип товара: physical, digital, service или category. Обязательное поле.
  • caption — название.
  • article — артикул.
  • otherId — код во внешней системе, строка. Должен быть уникальным в магазине.
  • price, oldPrice — цена и старая цена, числа.
  • description — описание.
  • modelId — ID категории.
  • parentGoodId — ID товара-родителя, если создаётся вариант. У одного товара — до 200 вариантов.
  • onModeration — true, чтобы создать товар скрытым с витрины.
  • physical — склад физического товара: trackStock (учитывать остаток, по умолчанию false), stockQty (начальный остаток), lowStockThreshold (порог малого остатка), weightGrams, lengthMm, widthMm, heightMm.
POST https://myshop.ru/api/v2/goods
X-Service-Token: ваш_токен
Content-Type: application/json

{
  "type": "physical",
  "caption": "Футболка базовая",
  "article": "TS-001",
  "otherId": "1C-000123",
  "price": 1990,
  "modelId": 7,
  "physical": {
    "trackStock": true,
    "stockQty": 12,
    "lowStockThreshold": 3
  }
}

Ответ — код 201 и созданный товар без блока physical. Остаток после создания проверяйте запросом GET /api/v2/goods?id=….

  • Если товар с таким otherId уже есть, придёт ошибка 409 good with this otherId already exists in the store. Для сценария «создать или обновить» сначала ищите товар по otherId, а при 409 переходите к изменению.
  • Если у категории есть обязательные характеристики, придёт ошибка 400 required specification "…" must be filled before publication. Создайте товар скрытым (onModeration: true), заполните характеристики в панели и после этого покажите товар на витрине.
  • Начальный остаток из physical.stockQty не попадает в историю движений и не создаёт событие «Изменение остатков».
  • Метод рассчитан прежде всего на физические товары. Цифровые товары и услуги удобнее создавать в панели: у них много собственных настроек.

После создания отправляется событие «Новый товар» (good.created).

Изменить товар

PUT /api/v2/goods?id=42

Права: «Товары и остатки» → «Редактирование».

Меняются только переданные поля, остальные остаются прежними. Поля те же, что при создании, но тип товара сменить нельзя. Пример — новая цена:

PUT https://myshop.ru/api/v2/goods?id=42
X-Service-Token: ваш_токен
Content-Type: application/json

{"price": 1790, "oldPrice": 1990}

Ответ — товар с новыми значениями, без блока physical. Смена цены остаток не трогает.

⚠️ Важно: не передавайте в этом методе поля остатка. Блок physical заменяется целиком: всё, что в нём не указано, обнулится, в том числе учёт остатка. А stockQty на верхнем уровне тела без trackStock отключит учёт остатка у товара. Остаток меняйте методом корректировки — он же запишет движение в историю и отправит событие.

  • В теле должно быть хотя бы одно поле товара, иначе ошибка 400 no valid fields provided for update.
  • Занятый otherId вернёт ошибку 409.
  • Событие «Изменение товара» (good.updated) отправляется после каждого успешного вызова, даже если значения не изменились. Если связка вызывает этот метод по этому же событию, получится бесконечный цикл.

Удалить товар

DELETE /api/v2/goods?id=42

Права: «Товары и остатки» → «Удаление».

Удаляет один товар вместе с его вариантами. Ответ: {"ok": true, "deleted": 1}. Список ID в одном запросе токен передать не может — вызывайте метод для каждого товара.

  • Активные записи на удалённую услугу отменяются. Методы записей описаны в статье «Методы API. Исполнители и записи».
  • Повторное удаление того же товара вернёт ошибку 403: удалённый товар для токена уже не принадлежит магазину.
  • Событие «Удаление товара» (good.deleted) придёт только для указанного товара, для его вариантов событий нет.

Остатки

Корректировка остатка

POST /api/v2/admin/goods/42/stock/adjust

Права: «Товары и остатки» → «Создание товаров и корректировка остатков». Права «Редактирование» для корректировки недостаточно.

Число в адресе — ID товара или варианта. Метод работает так же, как кнопки «Приход» и «Списание» на вкладке «Склад» карточки товара.

  • delta — целое число, не ноль: положительное — приход, отрицательное — списание. Обязательное поле.
  • reason — причина. Если не указать, запишется manual_adjust. Значение сохраняется как есть, например income или return.
  • comment — комментарий к движению.
POST https://myshop.ru/api/v2/admin/goods/42/stock/adjust
X-Service-Token: ваш_токен
Content-Type: application/json

{"delta": 5, "reason": "income", "comment": "Поставка №15"}

Ответ: {"newQty": 17, "delta": 5, "reason": "income"}, где newQty — остаток после корректировки.

Движение появится в истории остатка, а магазин отправит события «Изменение остатков» и, если остаток опустился до порога, «Малый остаток». Ошибки у этого метода приходят в поле error:

  • 400 {"error": "stock_not_tracked"} — у товара не включён учёт остатка;
  • 409 {"error": "out_of_stock"} — остаток ушёл бы ниже нуля, корректировка не выполнена;
  • 500 goodtype: good not found — товар не физический: у цифровых товаров и услуг остатка нет.

💡 Метода «установить остаток» нет. Чтобы выставить точное значение из учётной системы, прочитайте текущий physical.stockQty, вычислите разницу и передайте её в delta. У товаров с вариантами корректируйте каждый вариант по его ID.

История движений остатка

GET /api/v2/admin/goods/42/stock/log?limit=50

Права: «Товары и остатки» → «Чтение».

Возвращает последние движения товара, новые сверху. Параметр limit задаёт число записей, по умолчанию 50. Постраничного перебора нет.

{
  "count": 2,
  "rows": [
    {
      "id": 1235,
      "goodId": 42,
      "delta": 5,
      "stockQtyAfter": 17,
      "reason": "income",
      "comment": "Поставка №15",
      "operatorUserId": null,
      "orderId": null,
      "createdAt": "2026-09-16T08:35:00.123456Z"
    },
    {
      "id": 1234,
      "goodId": 42,
      "delta": -2,
      "stockQtyAfter": 12,
      "reason": "order_created",
      "comment": "order reservation",
      "operatorUserId": null,
      "orderId": 122,
      "createdAt": "2026-09-15T12:00:00.5Z"
    }
  ]
}

Поле id совпадает с movementId в событиях остатков, count — число записей в этом ответе. В operatorUserId указан сотрудник, чьё действие в панели привело к движению. Для запросов по токену и заказов с витрины там null.

Значения reason и их подписи в истории на вкладке «Склад»:

  • income — «Приход»: кнопка «Приход» в панели;
  • manual_adjust — «Списание вручную»: кнопка «Списание» или корректировка по API без причины;
  • return — «Возврат»;
  • order_created — «Списание по заказу»: резерв при оформлении заказа или увеличении количества;
  • order_cancelled — «Возврат по отмене»: возврат резерва при отмене заказа, уменьшении количества или удалении позиции;
  • order_paid — «Списание по заказу» в старых записях, до перехода на резерв при оформлении.

Любое другое значение, переданное через API, история покажет как есть.

Остаток, заданный при создании или изменении товара и при импорте каталога, в историю не попадает.

Что по токену недоступно

Эти операции с каталогом выполняются только в панели, API ответит 403 service token is not allowed on this route:

  • категории: получить список категорий и их ID, создать или изменить категорию;
  • массовые действия: перенос товаров в категорию, смена меток у нескольких товаров, создание вариантов пачкой;
  • стоп-лист, справочники характеристик и опций, фото и цифровое содержимое товаров;
  • импорт и экспорт каталога.

Короткие ответы

Как обновлять цены и остатки из учётной системы?

Храните в карточке товара код из учётной системы в поле otherId. Связка находит товар запросом GET /api/v2/goods с параметрами otherId и limit=1, меняет цену методом PUT /api/v2/goods?id=…, а для остатка вычисляет разницу с physical.stockQty и вызывает корректировку. Так изменение остатка попадёт в историю движений и отправит событие.

Почему корректировка остатка возвращает 403 при правах на редактирование?

Корректировка относится к флажку «Создание товаров и корректировка остатков», а не к «Редактированию». Выпустите токен с этим флажком. В ответе 403 поле requiredCapability покажет недостающее право: catalog.inventory.adjust.

Где взять ID категории для нового товара?

Из ответа о любом товаре этой категории: отдельного списка категорий в API нет. Возьмите поле modelId у товара этой категории в ответе GET /api/v2/goods или создайте товар без категории и перенесите его в панели.