MSInventory

Публичная документация

MSInventory API v1

Полная документация публичного API

Эта страница доступна без личного кабинета и описывает внешний API для витрин, маркетплейсов, ботов и партнёрских сервисов. Управление ключами остаётся в кабинете, а интеграции используют только API-ключи с ограниченными scopes.

Базовый URL

http://192.168.0.129:9006/v1

Версия

v1 / OpenAPI 3.1

Доступ

X-API-Key

Авторизация и соглашения

Базовый URLrequired
http://192.168.0.129:9006/v1
API-ключrequired
Передавайте ключ в заголовке X-API-Key. Пример: X-API-Key: msi_live_....
Tenant
Для API-ключей tenant определяется автоматически. Заголовок X-Tenant-Id нужен только для пользовательской авторизации, если один пользователь имеет несколько организаций.
Project scope
Ключ может быть привязан к проекту. Тогда списки и операции заказов ограничены этим projectId, а попытка передать другой projectId вернёт 403 projects.scope_mismatch.
Decimal
Все денежные и количественные значения передаются строками, чтобы не терять точность: "1490.00", "1", "12.500000".
Идемпотентность
POST /public/orders и /public/orders/{salesOrderId}/reserve требуют Idempotency-Key. Повтор с тем же ключом и тем же телом вернёт исходный результат.
Трассировка
Каждый ответ содержит X-Request-Id. Указывайте его при обращении в поддержку или при разборе интеграционных ошибок.

Права доступа (scopes)

Scopes выбираются при создании API-ключа. Метод вернёт 403 auth.permission_denied, если нужный scope не выдан ключу.

ScopeЧто разрешает
Товары: чтениеproducts.readСписок товаров и карточки SKU через GET /v1/public/products.
Остатки: чтениеstocks.readТекущие остатки по складам через GET /v1/public/stocks.
Заказы: чтениеorders.readСписок и карточка продаж через GET /v1/public/orders.
Заказы: создание и операцииorders.writeСоздание заказа, резервирование и отмена через POST /v1/public/orders.

Endpoint-ы

GET/public/products

Список товаров

Возвращает товары с вариантами SKU. Используйте для витрин, маркетплейсов и синхронизации каталога.

scope products.read

Query-параметры

search
Поиск по названию, артикулу и связанным полям каталога.
status
Фильтр статуса товара: draft, active или archived.
categoryId
UUID категории.
limit
Количество записей в ответе, от 1 до 500.

Ответы

200
Объект с массивом data, где каждый элемент соответствует Product.
401
API-ключ не передан, неверен или отозван.
403
У ключа нет scope products.read.
429
Превышен лимит чтения.

Пример

curl -sS "$BASE_URL/public/products?search=mug&status=active&limit=20" \
  -H "X-API-Key: $MSI_API_KEY"
GET/public/products/{productId}

Карточка товара

Возвращает один товар по UUID вместе с вариантами SKU и ценами по умолчанию.

scope products.read

Path-параметры

productIdrequired
UUID товара.

Ответы

200
Product.
404
Товар не найден.
429
Превышен лимит чтения.

Пример

curl -sS "$BASE_URL/public/products/00000000-0000-0000-0000-000000000000" \
  -H "X-API-Key: $MSI_API_KEY"
GET/public/stocks

Остатки

Возвращает текущие остатки по складам и SKU: onHand, reserved, incoming и available.

scope stocks.read

Query-параметры

warehouseId
UUID склада.
variantId
UUID варианта SKU.
productId
UUID товара.
search
Поиск по связанному товару или SKU.
limit
Количество записей в ответе, от 1 до 500.

Ответы

200
Объект с массивом data, где каждый элемент соответствует StockBalance.
403
У ключа нет scope stocks.read.
429
Превышен лимит чтения.

Пример

curl -sS "$BASE_URL/public/stocks?variantId=00000000-0000-0000-0000-000000000000&limit=50" \
  -H "X-API-Key: $MSI_API_KEY"
GET/public/orders

Список заказов

Возвращает продажи. Если API-ключ привязан к проекту, сервер автоматически ограничивает выдачу этим проектом.

scope orders.read

Query-параметры

search
Поиск по номеру заказа, внешнему номеру и клиентским данным.
projectId
UUID проекта. Для project-scoped ключей должен совпадать с проектом ключа.
channelCode
Код канала продаж, например web, marketplace или api.
status
Статус заказа: draft, reserved, shipped, cancelled и другие.
limit
Количество записей в ответе, от 1 до 500.

Ответы

200
Объект с массивом data, где каждый элемент соответствует SalesOrder.
403
У ключа нет scope orders.read или projectId не совпадает с ключом.
429
Превышен лимит чтения.

Пример

curl -sS "$BASE_URL/public/orders?channelCode=web&status=reserved&limit=20" \
  -H "X-API-Key: $MSI_API_KEY"
GET/public/orders/{salesOrderId}

Карточка заказа

Возвращает заказ, склад, позиции, суммы и связанный проект.

scope orders.read

Path-параметры

salesOrderIdrequired
UUID заказа.

Ответы

200
SalesOrder.
403
Project-scoped ключ не имеет доступа к заказу.
404
Заказ не найден.
429
Превышен лимит чтения.

Пример

curl -sS "$BASE_URL/public/orders/00000000-0000-0000-0000-000000000000" \
  -H "X-API-Key: $MSI_API_KEY"
POST/public/orders

Создание заказа

Создаёт заказ покупателя. Для API-ключа нужен проект: он берётся из ключа, а склад берётся из warehouseId или defaultWarehouseId проекта.

scope orders.write

Заголовки

Idempotency-Keyrequired
Уникальный ключ операции длиной 8-160 символов.
Content-Typerequired
application/json.
X-Request-Id
Необязательный внешний идентификатор запроса для трассировки.

Тело запроса

channelCode
Код канала продаж, до 80 символов.
externalOrderId
Внешний номер заказа, до 160 символов. Сохраняется как mapping проекта.
warehouseId
UUID склада. Если не передан, используется склад проекта по умолчанию.
currency
Валюта заказа, по умолчанию RUB.
customer
Объект с name, email и phone.
comment
Комментарий до 2000 символов.
metadata
Произвольный JSON-объект для внешней системы.
itemsrequired
Массив от 1 до 100 позиций. В каждой позиции нужен variantId или sku, quantity и unitPrice.

Ответы

200
Созданный или повторно возвращённый SalesOrder.
400
Ошибка валидации, нет Idempotency-Key, склада или позиции заказа.
403
У ключа нет scope orders.write или нет проекта для создания заказа.
404
SKU не найден.
409
Конфликт идемпотентности.
429
Превышен лимит записи.

Пример

curl -sS -X POST "$BASE_URL/public/orders" \
  -H "X-API-Key: $MSI_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "channelCode": "web",
    "externalOrderId": "shop-1042",
    "currency": "RUB",
    "customer": {
      "name": "Иван Петров",
      "email": "ivan@example.com",
      "phone": "+79990000000"
    },
    "metadata": {
      "source": "checkout"
    },
    "items": [
      {
        "sku": "MUG-RED-L",
        "quantity": "1",
        "unitPrice": "1490.00"
      }
    ]
  }'
POST/public/orders/{salesOrderId}/reserve

Резервирование заказа

Резервирует остатки по черновику заказа. Операция идемпотентна.

scope orders.write

Path-параметры

salesOrderIdrequired
UUID заказа.

Заголовки

Idempotency-Keyrequired
Уникальный ключ операции.

Ответы

200
Обновлённый SalesOrder.
400
Не передан Idempotency-Key.
403
Project-scoped ключ не имеет доступа к заказу.
409
Недостаточно доступного остатка или конфликт идемпотентности.
429
Превышен лимит записи.

Пример

curl -sS -X POST "$BASE_URL/public/orders/00000000-0000-0000-0000-000000000000/reserve" \
  -H "X-API-Key: $MSI_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
POST/public/orders/{salesOrderId}/cancel

Отмена заказа

Отменяет заказ и снимает связанные резервы. Idempotency-Key можно передать, если внешняя система повторяет операции автоматически.

scope orders.write

Path-параметры

salesOrderIdrequired
UUID заказа.

Заголовки

Idempotency-Key
Необязательный ключ идемпотентности для повторов.

Ответы

200
Отменённый SalesOrder.
403
Project-scoped ключ не имеет доступа к заказу.
409
Заказ нельзя отменить из текущего состояния.
429
Превышен лимит записи.

Пример

curl -sS -X POST "$BASE_URL/public/orders/00000000-0000-0000-0000-000000000000/cancel" \
  -H "X-API-Key: $MSI_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

Схемы данных

Product

Карточка товара для публичного каталога.

idrequired
UUID товара.
namerequired
Название товара.
slug
Человекочитаемый slug.
description
Описание или null.
statusrequired
draft, active или archived.
primaryImageUrl
URL основного изображения или null.
variants
Массив ProductVariant.

ProductVariant

SKU внутри товара.

idrequired
UUID варианта.
skurequired
Артикул.
name
Название варианта или null.
status
Статус SKU.
costPriceDefault
Закупочная цена строкой Decimal.
salePriceDefault
Цена продажи строкой Decimal.
currency
Код валюты.

StockBalance

Остатки SKU на складе.

id
UUID записи остатка.
productId
UUID товара.
variantId
UUID SKU.
warehouseId
UUID склада.
onHand
Физический остаток строкой Decimal.
reserved
Зарезервированное количество строкой Decimal.
incoming
Ожидаемый приход строкой Decimal.
available
Доступно к продаже строкой Decimal.

SalesOrder

Заказ покупателя.

idrequired
UUID заказа.
salesOrderNumberrequired
Внутренний номер заказа.
statusrequired
draft, reserved, partially_shipped, shipped, cancelled, returned или partially_returned.
currency
Валюта заказа.
totalAmount
Итоговая сумма строкой Decimal.
channelCode
Канал продаж или null.
externalOrderId
Внешний номер заказа или null.
projectId
UUID проекта или null.
warehouse
Объект склада: id, code, name.
items
Массив SalesOrderItem.
createdAt
Дата создания в ISO 8601.

SalesOrderItem

Позиция заказа.

id
UUID позиции.
variantId
UUID SKU.
productId
UUID товара.
quantityOrdered
Заказанное количество строкой Decimal.
quantityReserved
Зарезервированное количество строкой Decimal.
quantityShipped
Отгруженное количество строкой Decimal.
unitPrice
Цена за единицу строкой Decimal.
currency
Валюта позиции.
totalAmount
Сумма позиции строкой Decimal.

Ошибки, лимиты и повторы

Формат ошибки

Ошибки всегда возвращаются в одном JSON-формате. Поле requestId совпадает с заголовком X-Request-Id.

{
  "error": {
    "code": "inventory.insufficient_stock",
    "message": "Available stock is insufficient",
    "details": {
      "variantId": "00000000-0000-0000-0000-000000000000"
    },
    "requestId": "req_01HX..."
  }
}

Rate limit

По умолчанию чтение ограничено 600 запросами в минуту на API-ключ, запись - 120 запросами в минуту. При превышении вернётся 429 и заголовок Retry-After.

X-RateLimit-Limit
Размер текущего окна лимита.
X-RateLimit-Remaining
Сколько запросов осталось.
X-RateLimit-Reset
Через сколько секунд окно сбросится.
Retry-After
Пауза перед повтором после 429.
КодОписание
400 validation.failedТело запроса или параметры не прошли валидацию.
400 idempotency.key_requiredДля write-операции не передан обязательный Idempotency-Key.
400 orders.warehouse_requiredНе указан warehouseId и у проекта нет склада по умолчанию.
401 auth.invalid_api_keyAPI-ключ отсутствует, неверен или отозван.
403 auth.permission_deniedУ ключа нет нужного scope.
403 projects.scope_mismatchProject-scoped ключ пытается работать с другим проектом.
403 orders.project_requiredЗаказ создаётся API-ключом без привязки к проекту.
404 variants.not_foundSKU из позиции заказа не найден.
409 inventory.insufficient_stockНедостаточно доступного остатка для резервирования.
409 idempotency.conflictТот же Idempotency-Key использован с другим телом запроса.
429 rate_limit.exceededПревышен лимит запросов по ключу.

Вебхуки

Вебхуки настраиваются в личном кабинете, а внешняя система принимает POST-запросы от MSInventory. Каждая доставка подписывается HMAC-SHA256 по строке timestamp.body.

X-MSInventory-Event
Код события.
X-MSInventory-Delivery
UUID доставки.
X-MSInventory-Timestamp
Unix timestamp подписи.
X-MSInventory-Signature
Значение вида sha256=<hex>.
X-MSInventory-Attempt
Номер попытки доставки.
X-Request-Id
Идентификатор запроса.

Проверка подписи на Node.js

import crypto from 'node:crypto';

const signedPayload = `${timestamp}.${rawBody}`;
const expected = 'sha256=' + crypto
  .createHmac('sha256', webhookSecret)
  .update(signedPayload)
  .digest('hex');

const ok = crypto.timingSafeEqual(
  Buffer.from(signature),
  Buffer.from(expected),
);

Повторы выполняются до 5 раз с экспоненциальной задержкой: 10s, 30s, 2m, 10m, 30m. После 25 подряд неуспешных доставок вебхук автоматически переводится в disabled.

СобытиеКогда отправляется
Заказ созданsales_order.createdСрабатывает после создания заказа через UI, импорт или публичное API.
Заказ зарезервированsales_order.reservedСрабатывает после успешного резервирования товаров под заказ.
Заказ отменёнsales_order.cancelledСрабатывает при ручной отмене или отмене через публичное API.
Заказ отгруженsales_order.shippedСрабатывает при полной или частичной отгрузке заказа.
Возврат по заказуsales_order.returnedСрабатывает после оприходования возврата.
Возврат от клиента созданsales_return.createdСрабатывает при создании возврата (независимо от связки с заказом).
Заказ поставщику созданpurchase_order.createdСрабатывает после сохранения черновика или утверждения заказа.
Приёмка по закупкеpurchase_order.receivedСрабатывает после проведения приёмки на склад.
Движение по складуstock.movement.createdСрабатывает на каждое складское движение, включая ручные корректировки.
Товар созданproduct.createdСрабатывает после создания карточки товара.
Товар обновлёнproduct.updatedСрабатывает при сохранении изменений в карточке.
Товар в архивеproduct.archivedСрабатывает при архивации товара.

OpenAPI и быстрый старт

Машинно-читаемая схема OpenAPI 3.1 доступна публично и подходит для Postman, Stoplight, swagger-ui и генераторов клиентов.

Минимальный старт

export BASE_URL="http://192.168.0.129:9006/v1"
export MSI_API_KEY="msi_live_..."

curl -sS "$BASE_URL/public/products?limit=5" \
  -H "X-API-Key: $MSI_API_KEY"