Практическое руководство API v2

1. Сервер, токен и первый запрос

Базовый URL — адрес вашей установки NWMS без /api/v2. Документация localhost описывает локальный код; доступность нового метода на другом сервере зависит от установленного выпуска. Используйте Bearer-токен своей учётной записи. Права и область данных пользователя сохраняются при обращении через API.

export NWMS_BASE_URL='https://YOUR-NWMS-HOST'
export NWMS_TOKEN='YOUR-TOKEN'
export NWMS_REQUEST_KEY='UNIQUE-KEY-FOR-ONE-OPERATION'
curl --globoff "${NWMS_BASE_URL}/api/v2/products?per_page=1" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header 'Accept: application/json'

2. Структура запроса и ответа

JSONПередавайте Content-Type: application/json. Изменяемые публичные поля находятся внутри data. Вложенные строки, массивы товаров и команды имеют собственные схемы — сверяйте конкретный метод.
GET item{"data": {...}, "meta": {"api_version": "v2"}}
GET collection{"data": [...], "links": {...}, "meta": {...}}
PUT / PATCHНе считайте PUT полной заменой автоматически. Для шаблонов уведомлений оба метода изменяют только переданные поля. Пропуск поля и явный null имеют разное значение; nullable указан в таблице схемы.
IDsID документа, строки, склада, партии и уникального SSCC обозначают разные сущности. Не подставляйте внешний ID маркетплейса вместо внутреннего WMS ID.

3. Фильтры, сортировка и выгрузка

Допустимые фильтры перечислены у каждого endpoint. Типовой формат — filter[field]; сортировка sort=-updated_at,id задаёт убывание даты и возрастание ID. include включает только разрешённые связи. Для уведомлений per_page по умолчанию 50, максимум 250; другие методы могут иметь иной предел. Передавайте query-параметры через URL-кодирование, особенно кириллицу, плюс в часовом поясе и квадратные скобки.

curl --get "${NWMS_BASE_URL}/api/v2/notification-templates" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header 'Accept: application/json' \
  --data-urlencode 'filter[status_id]=1' \
  --data-urlencode 'filter[name]=Приёмка' \
  --data-urlencode 'include=bindings' \
  --data-urlencode 'sort=-updated_at,id' \
  --data-urlencode 'per_page=50' \
  --data-urlencode 'page=1'

При выгрузке сохраняйте одинаковые фильтры и сортировку на всех страницах, переходите по links.next до null. Изменяющаяся база не является снимком: храните ID и updated_at, устраняйте повторения на своей стороне. after_id используйте только там, где он явно документирован. Для created_at/updated_at граница YYYY-MM-DD включает весь день в часовом поясе приложения; явно согласуйте часовой пояс сервера при синхронизации.

4. Идемпотентность и восстановление после таймаута

Для обычных изменяющих v2-операций с этим middleware Idempotency-Key необязателен, но рекомендуется; максимум 191 символ. Успешный ответ хранится сутки в области пользователя, HTTP-метода и пути. Повтор должен содержать тот же URL и те же байты тела: даже другая сериализация одинакового JSON может дать конфликт. Ответ повтора содержит Idempotency-Replayed: true. Ошибочные ответы не сохраняются как успешный результат.

IDEMPOTENCY_KEY_CONFLICT / 409Ключ уже использован с другим URL/телом. Для новой логической операции создайте новый ключ; при повторе восстановите исходный запрос.
IDEMPOTENCY_KEY_IN_PROGRESS / 409Предыдущая операция ещё выполняется. Дождитесь результата; не создавайте дубликат с новым ключом.
Cross-dockIdempotency-Key обязателен, включая создание приёмки type_id=3. Командный контракт дополнительно требует UUID command_id и для версионируемых ресурсов актуальную version. Подробности — кросс-докинг.

5. Обработка ошибок

401Проверьте токен и заголовок Authorization.
403Проверьте разрешение на модуль и действие; смена ID не даёт дополнительных прав.
404Объект отсутствует или не входит в область видимости. Проверьте домен, ID родителя и вложенного объекта.
422Исправьте поля из errors. Автоматический повтор неизменного тела обычно бесполезен.
409Разберите код конфликта. Для устаревшей version перечитайте ресурс; для выполняющейся команды дождитесь результата.
429Снизьте частоту и учитывайте Retry-After, если сервер его вернул. Используйте ограниченное число повторов с растущей задержкой.
5xx / timeoutРезультат записи может быть неизвестен. Сначала сверяйте ресурс и повторяйте исходный запрос с тем же ключом. Сохраняйте время, метод, путь, HTTP-код и тело ответа без токена.

Не полагайтесь на один универсальный error: cross-dock использует meta.error_code, а обычный конфликт ключа — error. Точная схема и примеры приведены у каждой операции.

Документы, партии и фактические остатки

stocks.physical / stocks.aggregateМассивы складских итогов: warehouse_id, warehouse_name, stockTotal, stockReserved, stockAvailable. stocks.available_by_warehouse — объект с ключами ID складов. Не воспринимайте эти три поля как одинаковую структуру.
GET /api/v2/products/{id}/stock-lotsФизически размещённый товар по партиям и датам. Резерв без конкретной партии нельзя вычитать из произвольно выбранной партии. Сверяйте единицы количества и склад в ответе.
accepted_lotsФактические партии приёмки. Ожидание, фактическая приёмка и размещение — разные показатели. Их расхождение само по себе не означает ошибку API.
requested_lot / fulfillment_lotsВ строке заказа requested_lot описывает требование, fulfillment_lots — фактический подбор; picked_quantity — подобранное количество. Несколько фактических партий нельзя сводить к одной дате.
movement_type / operationПодбор может давать пару снятия резерва и физического списания. Различайте operation; не считайте обе строки двумя списаниями. Перемещения объединяются через movement_group_id; transfer_kind уточняет вид.
GET /api/v2/closed-boxesРеальные закрытые короба с уникальным SSCC: balance=1, balance_unit=box. Штрихкод типа упаковки из products не является уникальным SSCC. Открытые, отгруженные и только ожидаемые короба не входят в текущий закрытый остаток.
acceptance_dateПри создании обычной/возвратной приёмки (type_id=1/2) текущий обработчик ставит серверное now(), даже если передана acceptance_date. Изменение существующей приёмки принимает дату. Создание type_id=3 использует отдельный cross-dock сервис. created_at/updated_at — технические метки, не дата документа.
LifecycleОтмена приёмки — отдельная команда cancel с проверкой состояния; она не равна удалению. Для строк используйте /lines, а устаревшие /offers сохраняются для совместимости. Подробные ограничения смотрите у операции.