Skip to content

Каталог ​

Публичные catalog routes v2 отдают дерево и разделы каталога nnz-ipc.ru.

Общие правила ​

  • Публичный идентификатор раздела - строковое значение id.
  • Счетчики товаров считаются только по активным товарам.
  • availableProductCount считает товары, у которых есть положительный остаток хотя бы на одном складе.
  • slug вычисляется как последний сегмент url.path, но не является уникальным идентификатором.
  • Лента изменений товаров хранится 90 дней по умолчанию. Для регулярной синхронизации используйте cursor, а не дату.

Все ответы используют общую JSON-обертку API:

json
{
  "status": true,
  "data": {},
  "error": {},
  "message": ""
}

Раздел каталога ​

Базовый объект раздела:

json
{
  "id": "37057",
  "parentSectionId": null,
  "name": "Продукция",
  "url": {
    "full": "https://nnz-ipc.ru/catalogue/",
    "host": "nnz-ipc.ru",
    "path": "/catalogue/",
    "slug": "catalogue"
  },
  "isActive": true,
  "sortOrder": 288,
  "level": 1,
  "hasChildren": true,
  "childSectionIds": ["103070", "95228"],
  "directProductCount": 4657,
  "productCount": 4657,
  "availableProductCount": 838,
  "syncedAt": "2026-07-08T19:34:23.469Z"
}

Поля счетчиков:

ПолеЗначение
directProductCountАктивные публичные товары, привязанные прямо к разделу
productCountАктивные публичные товары в разделе и его публичном поддереве
availableProductCountАктивные публичные товары в поддереве с положительным остатком

Дерево каталога ​

http
GET /api/v2/catalog/tree

Ограничить глубину дерева:

http
GET /api/v2/catalog/tree?depth=2

Добавить производителей:

http
GET /api/v2/catalog/tree?depth=2&include=vendors

Пример ответа:

json
{
  "status": true,
  "data": {
    "items": [
      {
        "id": "37057",
        "parentSectionId": null,
        "name": "Продукция",
        "url": {
          "full": "https://nnz-ipc.ru/catalogue/",
          "host": "nnz-ipc.ru",
          "path": "/catalogue/",
          "slug": "catalogue"
        },
        "isActive": true,
        "sortOrder": 288,
        "level": 1,
        "hasChildren": true,
        "childSectionIds": ["103070", "95228"],
        "directProductCount": 4657,
        "productCount": 4657,
        "availableProductCount": 838,
        "syncedAt": "2026-07-08T19:34:23.469Z",
        "children": [
          {
            "id": "95228",
            "parentSectionId": "37057",
            "name": "Коммуникационное оборудование",
            "url": {
              "full": "https://nnz-ipc.ru/catalogue/comm/",
              "host": "nnz-ipc.ru",
              "path": "/catalogue/comm/",
              "slug": "comm"
            },
            "isActive": true,
            "sortOrder": 3,
            "level": 2,
            "hasChildren": true,
            "childSectionIds": ["95271", "95262"],
            "directProductCount": 1583,
            "productCount": 1583,
            "availableProductCount": 429,
            "syncedAt": "2026-07-08T19:34:26.358Z",
            "children": []
          }
        ]
      }
    ],
    "meta": {
      "format": "tree",
      "host": "nnz-ipc.ru",
      "total": 255
    }
  },
  "error": {},
  "message": ""
}

Плоский список разделов ​

http
GET /api/v2/catalog/sections

С производителями:

http
GET /api/v2/catalog/sections?include=vendors

Ответ:

json
{
  "status": true,
  "data": {
    "items": [
      {
        "id": "37057",
        "parentSectionId": null,
        "name": "Продукция",
        "url": {
          "full": "https://nnz-ipc.ru/catalogue/",
          "host": "nnz-ipc.ru",
          "path": "/catalogue/",
          "slug": "catalogue"
        },
        "isActive": true,
        "sortOrder": 288,
        "level": 1,
        "hasChildren": true,
        "childSectionIds": ["103070", "95228"],
        "directProductCount": 4657,
        "productCount": 4657,
        "availableProductCount": 838,
        "syncedAt": "2026-07-08T19:34:23.469Z"
      }
    ],
    "meta": {
      "format": "flat",
      "host": "nnz-ipc.ru",
      "total": 255
    }
  },
  "error": {},
  "message": ""
}

Один раздел ​

http
GET /api/v2/catalog/sections/:id

Пример:

http
GET /api/v2/catalog/sections/37057

Дополнительные данные подключаются через include:

http
GET /api/v2/catalog/sections/37057?include=children,breadcrumbs,vendors

Поддерживаемые значения include:

ЗначениеЧто добавляет
childrenПрямые дочерние разделы
breadcrumbsХлебные крошки от корня до текущего раздела
vendorsПроизводителей по публичному поддереву раздела

Фрагмент ответа:

json
{
  "status": true,
  "data": {
    "id": "37057",
    "parentSectionId": null,
    "name": "Продукция",
    "url": {
      "full": "https://nnz-ipc.ru/catalogue/",
      "host": "nnz-ipc.ru",
      "path": "/catalogue/",
      "slug": "catalogue"
    },
    "isActive": true,
    "sortOrder": 288,
    "level": 1,
    "hasChildren": true,
    "childSectionIds": ["103070", "95228"],
    "directProductCount": 4657,
    "productCount": 4657,
    "availableProductCount": 838,
    "syncedAt": "2026-07-08T19:34:23.469Z",
    "breadcrumbs": [
      {
        "id": "37057",
        "name": "Продукция",
        "url": {
          "full": "https://nnz-ipc.ru/catalogue/",
          "host": "nnz-ipc.ru",
          "path": "/catalogue/",
          "slug": "catalogue"
        }
      }
    ],
    "vendors": [
      {
        "id": "moxa",
        "name": "MOXA",
        "productCount": 1433,
        "availableProductCount": 394
      }
    ],
    "children": []
  },
  "error": {},
  "message": ""
}

Если раздел не входит в публичный каталог nnz-ipc.ru, API возвращает 404.

json
{
  "status": false,
  "data": {},
  "error": {
    "code": 404,
    "name": "CatalogSectionNotFoundError",
    "message": "Раздел каталога не найден"
  },
  "message": ""
}

Производители раздела ​

http
GET /api/v2/catalog/sections/:id/vendors

Пример:

http
GET /api/v2/catalog/sections/37057/vendors

Ответ:

json
{
  "status": true,
  "data": {
    "items": [
      {
        "id": "moxa",
        "name": "MOXA",
        "productCount": 1433,
        "availableProductCount": 394
      },
      {
        "id": "unknown",
        "name": "unknown",
        "productCount": 2,
        "availableProductCount": 0
      }
    ],
    "meta": {
      "sectionId": "37057"
    }
  },
  "error": {},
  "message": ""
}

Если у товара производитель пустой, он попадает в группу:

json
{
  "id": "unknown",
  "name": "unknown"
}

Изменения товаров ​

Для обычного чтения актуальных карточек раздела используйте авторизованный GET /api/v2/catalog/sections/:id/products. Фильтр по времени изменения в этот список намеренно не добавлен: события переноса и удаления корректно доступны только через ленту ниже.

Лента изменений позволяет узнать, какие товары в публичном поддереве раздела изменились после предыдущего запроса. Она учитывает только публичные товары и сохраняет удаленные товары как события removed.

Поддерживаются типы изменений:

ТипЗначение
contentИзменилось публичное представление: фото, характеристики, описание, название, URL, производитель или разделы. Новый и восстановленный товар также приходят с этим типом.
commercialИзменились цены, остатки, наличие или данные складов.
removedТовар перестал быть доступен в публичном API.

Если у товара одновременно изменились карточка и цены, он учитывается в обоих счетчиках, но в total считается один раз.

Сводка изменений ​

http
GET /api/v2/catalog/sections/:id/product-changes/summary?cursor=:cursor

Первый раз можно задать ISO-дату:

http
GET /api/v2/catalog/sections/103070/product-changes/summary?since=2026-07-09T00:00:00.000Z

В последующих запросах передавайте сохраненный meta.nextCursor:

http
GET /api/v2/catalog/sections/103070/product-changes/summary?cursor=eyJ...opaque...

Ответ:

json
{
  "status": true,
  "data": {
    "content": 12,
    "commercial": 31,
    "removed": 2,
    "total": 38,
    "meta": {
      "sectionId": "103070",
      "nextCursor": "eyJ...opaque..."
    }
  },
  "error": {},
  "message": ""
}

nextCursor фиксирует все события, учтенные в этой сводке. Его можно сохранить как новую точку синхронизации, если клиенту достаточно количества.

Лента событий ​

http
GET /api/v2/catalog/sections/:id/product-changes?cursor=:cursor&limit=100

limit по умолчанию равен 100, допустимый диапазон - от 1 до 500. Вместо cursor в первом запросе также допускается since в ISO-формате. Параметры cursor и since нельзя передавать вместе.

Пример:

http
GET /api/v2/catalog/sections/103070/product-changes?since=2026-07-09T00:00:00.000Z&limit=2

Ответ:

json
{
  "status": true,
  "data": {
    "items": [
      {
        "eventId": "841",
        "stockNumber": "6167195",
        "sectionIds": ["103070", "189795"],
        "changeTypes": ["content", "commercial"],
        "operation": "upsert",
        "changedAt": "2026-07-09T10:20:31.456Z"
      },
      {
        "eventId": "842",
        "stockNumber": "6116191",
        "sectionIds": ["103070"],
        "changeTypes": ["removed"],
        "operation": "remove",
        "changedAt": "2026-07-09T10:22:05.814Z"
      }
    ],
    "meta": {
      "sectionId": "103070",
      "hasMore": true,
      "nextCursor": "eyJ...opaque-page...",
      "checkpoint": "eyJ...opaque-checkpoint..."
    }
  },
  "error": {},
  "message": ""
}

Пока hasMore = true, передавайте nextCursor для следующей страницы. После последней страницы сохраните checkpoint: он покрывает весь зафиксированный диапазон, включая события из предыдущих страниц. Cursor непрозрачен и не должен разбираться или изменяться клиентом.

Событие содержит идентификатор и факт изменения, а не копию карточки до и после. При operation: "upsert" клиент использует stockNumber для обновления своей копии товара; при operation: "remove" удаляет товар из своей копии.

Фильтры раздела ​

Описание фильтров подключается только явным include=filters:

http
GET /api/v2/catalog/sections/:id?include=filters

Пример:

http
GET /api/v2/catalog/sections/178225?include=filters

Ответ:

json
{
  "status": true,
  "data": {
    "id": "178225",
    "name": "Компактные",
    "filters": [
      {
        "uid": "124786f0-d1ef-11e7-9887-00155d0c1500",
        "name": "Класс защиты",
        "groupName": "Компьютеры и комплектующие",
        "dataType": "relation",
        "isMultiple": false,
        "mainFilter": false,
        "hidden": true,
        "values": [
          {
            "value": "IP40",
            "key": "ip40",
            "count": 11
          }
        ]
      }
    ]
  },
  "error": {},
  "message": ""
}

Схема, названия, типы и порядок берутся из section_meta. Возможные значения и счетчики агрегируются из актуального product_filter_values только по публичным товарам выбранного раздела. Поле key используется в фильтрующих запросах и совпадает с filterValues[].key объекта товара.

Параметры ​

ПараметрГде используетсяЗначение
depth/treeМаксимальная глубина дерева
include=vendors/tree, /sections, /sections/:idДобавляет производителей
include=children/sections/:idДобавляет прямые дочерние разделы
include=breadcrumbs/sections/:idДобавляет хлебные крошки
include=filters/sections/:idДобавляет определения фильтров и актуальные значения
cursor/sections/:id/product-changes*Непрозрачная точка инкрементальной синхронизации
since/sections/:id/product-changes*ISO-дата для первого разового запроса
limit/sections/:id/product-changesРазмер страницы, от 1 до 500

Несколько значений include передаются через запятую:

http
GET /api/v2/catalog/sections/37057?include=children,breadcrumbs,vendors,filters

Ошибки ​

Catalog routes используют общий формат ошибок API.

СитуацияHTTPerror.name
Успешный запрос200-
Некорректный id, depth, cursor, since, limit или другой параметр запроса400ValidationError
Раздел не найден или не входит в публичный каталог404CatalogSectionNotFoundError
Cursor изменений старше срока хранения410ProductChangesCursorExpiredError
Внутренняя ошибка API500InternalServerError

404 возвращается не только для отсутствующих разделов, но и для разделов, которые есть в источнике, но скрыты из публичного каталога v2: неактивные разделы, разделы других доменов, разделы без URL и служебные архивные разделы.

Пример ошибки:

json
{
  "status": false,
  "data": {},
  "error": {
    "code": 404,
    "name": "CatalogSectionNotFoundError",
    "message": "Раздел каталога не найден"
  },
  "message": ""
}

Выберите версию API в верхнем меню.