
## Поля товара

`GET /v1/catalog-products/fields`

Возвращает справочник полей товара с подписями, типами, признаками доступности на чтение и запись, признаком «допускает `null`», описаниями и словарями `enum` там, где набор значений фиксирован, список полей, доступных для агрегации, а также операции, доступные в пакетном запросе.

## Примеры

### curl — личный ключ

```bash
curl "https://vibecode.bitrix24.tech/v1/catalog-products/fields" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth-приложение

```bash
curl "https://vibecode.bitrix24.tech/v1/catalog-products/fields" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — личный ключ

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/fields', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log('Полей:', Object.keys(data.fields).length)
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/catalog-products/fields', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()
```

## Поля ответа

`data.fields` — объект, ключ которого совпадает с именем поля, а значение содержит тип, признаки доступности на запись, подпись для отображения и — у полей с фиксированным набором значений — их словарь. Состав ключей разобран в таблице после списка полей. `data.aggregatable` — поля, по которым работает [агрегация](./aggregate.md). `data.batch` — операции, доступные в [пакетном запросе](/docs/batch).

| Поле | Тип | RO | Описание |
|------|-----|:--:|---------|
| `id` | number | да | Идентификатор товара |
| `name` | string | нет | Название товара |
| `active` | boolean | нет | Активен ли товар |
| `iblockId` | number | нет¹ | ID каталога. Список: [`GET /v1/catalogs`](/docs/entities/catalogs). Задаётся только при создании. Смена через `PATCH` отклоняется — товар нельзя перенести между каталогами |
| `iblockSectionId` | number \| null | нет | ID раздела каталога. `null` — товар не привязан к разделу. Список: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) |
| `purchasingPrice` | number \| null | нет | Закупочная цена. `null`, если не задана |
| `purchasingCurrency` | string \| null | нет | Валюта закупочной цены, например `RUB`. `null`, если закупочная цена не задана. Список: [`GET /v1/currencies`](/docs/entities/currencies) |
| `quantity` | number \| null | нет | Остаток на складе. `null`, если не задан |
| `weight` | number \| null | нет | Вес единицы товара. `null`, если не указан |
| `measure` | number | нет | ID единицы измерения |
| `available` | boolean | да | Доступен ли товар к покупке. Вычисляется Битрикс24 |
| `vatIncluded` | boolean | нет | НДС включён в цену |
| `bundle` | boolean | да | Является ли товар набором. Вычисляется Битрикс24 |
| `canBuyZero` | boolean | нет | Разрешить покупку при нулевом остатке |
| `quantityTrace` | boolean | нет | Включён учёт количества |
| `subscribe` | boolean | нет | Разрешить подписку на товар |
| `barcodeMulti` | boolean | нет | Разрешены отдельные штрихкоды для единиц товара |
| `withoutOrder` | boolean | нет | Доступен к заказу без наличия на складе |
| `dateActiveFrom` | datetime | нет | Дата начала активности товара |
| `dateActiveTo` | datetime | нет | Дата окончания активности товара |
| `createdBy` | number | да | ID пользователя, создавшего товар. Заполняется системой |
| `modifiedBy` | number | да | ID пользователя, изменившего товар. Заполняется системой |
| `dateCreate` | datetime | да | Дата создания товара |
| `timestampX` | datetime | да | Дата последнего изменения |
| `code` | string \| null | нет | Символьный код товара. `null`, если не задан |
| `xmlId` | string | нет | Внешний идентификатор |
| `sort` | number | нет | Порядок сортировки |
| `vatId` | number | нет | ID ставки НДС по умолчанию |
| `previewText` | string | нет | Текст анонса |
| `detailText` | string | нет | Подробное описание |
| `previewTextType` | string | нет | Формат текста анонса: `text` или `html` |
| `detailTextType` | string | нет | Формат подробного описания: `text` или `html` |
| `previewPicture` | object | нет | Изображение анонса |
| `detailPicture` | object | нет | Детальное изображение |
| `iblockSection` | object | нет | В справочнике `/fields` тип — `object`. Принимает массив ID разделов при создании и обновлении. На чтении не возвращается — основной раздел доступен как скалярный `iblockSectionId`. Список: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) |
| `width` | number | нет | Ширина товара |
| `height` | number | нет | Высота товара |
| `length` | number | нет | Длина товара |
| `quantityReserved` | number \| null | нет | Зарезервированное количество. `null`, если резерва нет |
| `recurSchemeLength` | number | нет | Длина периода оплаты. Только для коробочной версии Битрикс24 при продаже контента |
| `recurSchemeType` | string | нет | Единица времени периода оплаты: `H` — час, `D` — день, `W` — неделя, `M` — месяц, `Q` — квартал, `S` — полугодие, `Y` — год. Только для коробочной версии Битрикс24 при продаже контента |
| `trialPriceId` | number | нет | ID товара для пробной оплаты. Только для коробочной версии Битрикс24 при продаже контента |

¹ `iblockId` доступен для записи только при создании (`createOnly`) — в справочнике приходит с `readonly: false` и `createOnly: true`.

Заголовками запроса язык подписей и описаний не переключается. У значений `enum` подпись `label` английская, русская приходит отдельным ключом.

| Поле | Тип | Описание |
|------|-----|---------|
| `success` | boolean | Всегда `true` при успехе |
| `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean`, `datetime`, `object` |
| `data.fields.<имя>.label` | string | Короткая подпись поля на русском языке |
| `data.fields.<имя>.description` | string | Расширенное описание поля: назначение, где взять список допустимых значений, поведение при записи. Ключ есть у тех полей, у которых есть что добавить к подписи |
| `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и обновлении |
| `data.fields.<имя>.writeOnly` | boolean | `true` — поле принимается на запись, но не возвращается в ответах |
| `data.fields.<имя>.notReturned` | boolean | `true` — имя поля отсутствует во всех ответах чтения и не поддерживается в `select` |
| `data.fields.<имя>.createOnly` | boolean | `true` — поле принимается только при создании. В `PATCH` отклоняется с `READONLY_FIELD` (есть у `iblockId`) |
| `data.fields.<имя>.nullable` | boolean | `true` — поле может прийти со значением `null`. Ключ присутствует только у таких полей |
| `data.fields.<имя>.enum` | array | Словарь допустимых значений: массив `{ value, label }`. Ключ есть у полей с фиксированным набором — `previewTextType` и `detailTextType` (`text` и `html`). Отправлять нужно `value`, `label` предназначен для показа человеку |
| `data.aggregatable` | string[] | Поля, по которым работает [агрегация](./aggregate.md) |
| `data.batch` | string[] | Операции товара, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` |

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

```json
{
  "success": true,
  "data": {
    "fields": {
      "id": {
        "type": "number",
        "readonly": true,
        "label": "Идентификатор товара"
      },
      "iblockId": {
        "type": "number",
        "readonly": false,
        "createOnly": true,
        "label": "ID каталога",
        "description": "Каталог, которому принадлежит товар. Список: GET /v1/catalogs. Задаётся только при создании — смена через PATCH отклоняется, товар нельзя перенести между каталогами."
      },
      "purchasingPrice": {
        "type": "number",
        "readonly": false,
        "nullable": true,
        "label": "Закупочная цена",
        "description": "Закупочная цена товара; null, если не задана."
      },
      "iblockSection": {
        "type": "object",
        "readonly": false,
        "writeOnly": true,
        "notReturned": true,
        "label": "Разделы каталога",
        "description": "Массив ID разделов каталога, к которым относится товар. Принимается только при создании и обновлении — на чтении основной раздел приходит скаляром iblockSectionId. Список: GET /v1/catalog-sections."
      },
      "previewTextType": {
        "type": "string",
        "readonly": false,
        "label": "Формат текста анонса",
        "description": "Формат поля previewText.",
        "enum": [
          {
            "value": "text",
            "label": "Plain text",
            "labelRu": "Текст"
          },
          {
            "value": "html",
            "label": "HTML",
            "labelRu": "HTML"
          }
        ]
      }
    },
    "aggregatable": [
      "purchasingPrice",
      "quantity",
      "iblockSectionId"
    ],
    "batch": [
      "create",
      "update",
      "delete"
    ]
  }
}
```

Пример сокращён до пяти полей — по одному на признаки `readonly`, `createOnly`, `nullable`, одно с парой `writeOnly` + `notReturned` и одно с машиночитаемым словарём `enum`. В ответе приходят все сорок два.


## Пример ответа при ошибке

403 — нет скоупа:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'catalog' scope"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

**Запись зависит от управления складом.** Поля `quantity`, `purchasingPrice` и `purchasingCurrency` помечены в справочнике как доступные для записи, но при включённом на портале управлении складом не применяются при создании и изменении товара — остатки и закупочные цены ведутся складскими документами.

**Часть полей не приходит в списке по умолчанию.** Символьный код `code`, габариты `width`, `height`, `length`, тексты `previewText`, `detailText`, сортировка `sort` и ещё ряд полей из справочника не возвращаются в ответе `GET /v1/catalog-products` без явного `?select=`. Перечислите нужные имена в `?select=`, чтобы получить их в списке — эти поля доступны и в фильтрации, и в сортировке. В ответе одного товара `GET /v1/catalog-products/:id` они возвращаются всегда.

**Изображения и привязка к разделам не фильтруются.** `previewPicture` и `detailPicture` задаются при создании и обновлении и возвращаются в ответах — в `GET /v1/catalog-products/:id` и в списке по явному `?select=`, — но не поддерживают фильтрацию и сортировку. Поле `iblockSection` принимает массив ID разделов при создании и обновлении, но не возвращается в `GET /v1/catalog-products/:id` или списке. Для чтения, фильтрации и сортировки доступен скалярный `iblockSectionId` с ID основного раздела.

**Ответ `GET /:id` содержит поля сверх справочника.** Запрос одного товара дополнительно возвращает тип товара `type` и пользовательские свойства каталога вида `propertyNNN`. Они не входят в справочник полей `GET /v1/catalog-products/fields` и недоступны для фильтрации и сортировки.

**Каталог товара (`iblockId`) неизменяем.** Каталог выбирается при создании. Битрикс24 не переносит товар между каталогами через обновление. `PATCH` со сменой `iblockId` отклоняется с `400 READONLY_FIELD` — раньше такой запрос возвращал `200`, но товар оставался в прежнем каталоге (ложный успех).

**Поля аудита защищены.** `createdBy` и `modifiedBy` заполняются Битрикс24 и не принимаются при создании и обновлении — попытка передать их отклоняется с `400 READONLY_FIELD`.

## Смотрите также

- [Список товаров](/docs/entities/catalog-products/list)
- [Создать товар](/docs/entities/catalog-products/create)
- [Поиск товаров](/docs/entities/catalog-products/search)
- [Цены каталога](/docs/entities/catalog-prices)
- [Справочник сущностей](/docs/entities-index)
