
## Поля вариации

`GET /v1/catalog-offers/fields`

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

С параметром `iblockId` справочник дополняется полями конкретного каталога вариаций — его свойствами `propertyNNN`.

## Параметры

| Параметр | Тип | Обяз. | Описание |
|----------|-----|:-----:|---------|
| `iblockId` (query) | number | нет | ID информационного блока каталога вариаций: поле `catalogs[].iblockId` из [`GET /v1/catalogs`](/docs/entities/catalogs), а не `catalogs[].id` записи каталога; у этого каталога заполнен `productIblockId`. С ним ответ содержит свойства каталога `propertyNNN` и служебные поля `negativeAmountTrace`, `priceType`. Без параметра, с `iblockId` товарного каталога или с несуществующим значением приходит базовый набор из 44 полей и предупреждение `fields_partial` в `meta.warnings` |

В примерах `iblockId=27` — значение `catalogs[].iblockId` каталога вариаций. Если у записи каталога `id` отличается, подставьте значение `iblockId`.

## Примеры

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

```bash
curl "https://vibecode.bitrix24.tech/v1/catalog-offers/fields?iblockId=27" \
  -H "X-Api-Key: YOUR_API_KEY"
```

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

```bash
curl "https://vibecode.bitrix24.tech/v1/catalog-offers/fields?iblockId=27" \
  -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-offers/fields?iblockId=27', {
  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-offers/fields?iblockId=27', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

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

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

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

| Поле | Тип | RO | Описание |
|------|-----|:--:|---------|
| `id` | number | да | Идентификатор вариации |
| `name` | string | нет | Название вариации. Обязательно при создании |
| `active` | boolean | нет | Активна ли вариация |
| `iblockId` | number | нет¹ | ID каталога вариаций. Список: [`GET /v1/catalogs`](/docs/entities/catalogs). Обязателен при создании, задаётся только при создании |
| `parentId` | object \| null | нет² | Связь с головным товаром: `value` — ID головного товара строкой, `valueId` — служебный ID значения связи, только для чтения. При создании передаётся `{ "value": "<ID>" }`. `null` — свободная вариация. ID головного товара: [`GET /v1/catalog-skus`](/docs/entities/catalog-skus/list) |
| `type` | number | да | Тип записи, вычисляется Битрикс24: `4` — вариация привязана к головному товару, `5` — свободная вариация. В фильтре принимается одно точное значение |
| `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 единицы измерения. Список: [`GET /v1/catalog-measures`](/docs/entities/catalog-measures) |
| `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 пользователя, создавшего вариацию. Список: [`GET /v1/users`](/docs/entities/users) |
| `modifiedBy` | number | да | ID пользователя, изменившего вариацию последним. Список: [`GET /v1/users`](/docs/entities/users) |
| `dateCreate` | datetime | да | Дата создания. В фильтре не принимается |
| `timestampX` | datetime | да | Дата последнего изменения. В фильтре не принимается |
| `code` | string \| null | нет | Символьный код. `null`, если не задан |
| `xmlId` | string | нет | Внешний идентификатор |
| `sort` | number | нет | Порядок сортировки |
| `vatId` | number | нет | ID ставки НДС. Список: [`GET /v1/catalog-vat-rates`](/docs/entities/catalog-vat-rates) |
| `previewText` | string | нет | Текст анонса |
| `detailText` | string | нет | Подробное описание |
| `previewTextType` | string | нет | Формат текста анонса: `text` или `html` |
| `detailTextType` | string | нет | Формат подробного описания: `text` или `html` |
| `previewPicture` | object | нет | Изображение анонса |
| `detailPicture` | object | нет | Детальное изображение |
| `iblockSection` | 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 при продаже контента |
| `negativeAmountTrace` | char | да | Служебное поле каталога. Приходит только с `iblockId` |
| `priceType` | char | нет | Служебное поле каталога. Приходит только с `iblockId` |
| `propertyNNN` | productproperty | нет | Свойство каталога, где `NNN` — `id` свойства из [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties). Приходит только с `iblockId`, у множественных свойств — с `multiple: true` |

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

² `parentId` доступен для записи только при создании — в справочнике приходит с `readonly: false` и `readonlyOnUpdate: true`.

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

| Поле | Тип | Описание |
|------|-----|---------|
| `success` | boolean | Всегда `true` при успехе |
| `data.fields.<имя>.type` | string | Тип поля: `number`, `string`, `boolean`, `datetime`, `object`. У полей каталога — `char` и `productproperty` |
| `data.fields.<имя>.label` | string | Короткая подпись поля. У полей каталога подпись совпадает с именем поля |
| `data.fields.<имя>.description` | string | Расширенное описание поля: назначение, где взять список допустимых значений, поведение при записи. Ключ есть у тех полей, у которых есть что добавить к подписи |
| `data.fields.<имя>.readonly` | boolean | `true` — поле заполняется системой и не принимается при создании и изменении |
| `data.fields.<имя>.required` | boolean | `true` — поле обязательно при создании. Есть у `name` и `iblockId` |
| `data.fields.<имя>.createOnly` | boolean | `true` — поле принимается только при создании, в `PATCH` отклоняется с `READONLY_FIELD`. Есть у `iblockId` |
| `data.fields.<имя>.readonlyOnUpdate` | boolean | `true` — поле принимается при создании, в `PATCH` отклоняется с `READONLY_FIELD`. Есть у `parentId` |
| `data.fields.<имя>.properties` | object | Вложенные ключи поля-объекта с их типами. У `parentId` — `value` и `valueId`, второй с `readonly: true` |
| `data.fields.<имя>.writeOnly` | boolean | `true` — поле принимается на запись и не читается из ответов. Есть у `iblockSection` |
| `data.fields.<имя>.notReturned` | boolean | `true` — имя поля не поддерживается в `select`: в списке оно приходит предупреждением `UNKNOWN_SELECT_FIELD`. Есть у `iblockSection` |
| `data.fields.<имя>.nullable` | boolean | `true` — поле может прийти со значением `null`. Ключ присутствует только у таких полей |
| `data.fields.<имя>.multiple` | boolean | `true` — свойство каталога принимает несколько значений. Ключ присутствует только у таких свойств |
| `data.fields.<имя>.enum` | array | Словарь допустимых значений: массив `{ value, label, labelRu }`. Есть у `previewTextType` и `detailTextType`. Отправлять нужно `value`, подписи предназначены для показа человеку |
| `data.aggregatable` | string[] | Поля для `groupBy` в [агрегации](./aggregate.md): `purchasingPrice`, `quantity`, `iblockSectionId` |
| `data.batch` | string[] | Операции вариации, доступные в [пакетном запросе](/docs/batch): `create`, `update`, `delete` |
| `meta.warnings` | array | Предупреждения. Элемент с `code: fields_partial` приходит, когда ответ собран без полей каталога — без `iblockId` или с `iblockId`, который не принадлежит каталогу вариаций |

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

```json
{
  "success": true,
  "data": {
    "fields": {
      "id": {
        "type": "number",
        "readonly": true,
        "label": "Идентификатор товара",
        "description": "Уникальный идентификатор товара каталога."
      },
      "iblockId": {
        "type": "number",
        "readonly": false,
        "createOnly": true,
        "required": true,
        "label": "ID каталога",
        "description": "Каталог, которому принадлежит товар. Список: GET /v1/catalogs. Задаётся только при создании — смена через PATCH отклоняется, товар нельзя перенести между каталогами."
      },
      "parentId": {
        "type": "object",
        "readonly": false,
        "readonlyOnUpdate": true,
        "nullable": true,
        "label": "ID головного товара",
        "description": "Связь с головным SKU или товаром. При создании передайте {\"value\":\"<ID родителя>\"}; пропустите поле для свободной вариации. Битрикс24 возвращает value и valueId. Изменение этого поля отклоняется: Битрикс24 молча его игнорирует.",
        "properties": {
          "value": { "type": "string" },
          "valueId": { "type": "string", "readonly": true }
        }
      },
      "type": {
        "type": "number",
        "readonly": true,
        "label": "Тип товара Битрикс24",
        "description": "Вычисляется Битрикс24. Свободная вариация имеет другой тип, чем привязанная к родителю. В фильтре принимается только точный тип 4 или 5."
      },
      "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" }
        ]
      },
      "property909": {
        "type": "productproperty",
        "readonly": false,
        "multiple": true,
        "label": "property909"
      }
    },
    "aggregatable": [
      "purchasingPrice",
      "quantity",
      "iblockSectionId"
    ],
    "batch": [
      "create",
      "update",
      "delete"
    ]
  }
}
```

Пример сокращён до семи полей — по одному на признаки `readonly`, `createOnly` с `required`, `readonlyOnUpdate` с `properties`, вычисляемый `type`, пару `writeOnly` + `notReturned`, словарь `enum` и множественное свойство каталога. С `iblockId=27` на тестовом портале приходит 55 полей.

Без `iblockId` ответ содержит предупреждение:

```json
{
  "success": true,
  "data": { "fields": { /* 44 поля */ }, "aggregatable": [ /* ... */ ], "batch": [ /* ... */ ] },
  "meta": {
    "warnings": [
      {
        "code": "fields_partial",
        "message": "Dynamic field metadata from Bitrix24 was unavailable; the response carries static schema fields only and some labels may be missing. Retry to obtain the complete set."
      }
    ]
  }
}
```

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

401 — не передан ключ:

```json
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key required. Pass via X-Api-Key header."
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `catalog` |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 429 | `RATE_LIMITED` | Превышен лимит запросов: 300 в минуту на портал, все API-ключи портала делят один лимит. Точное значение — в заголовке `x-ratelimit-limit` (потолок делится на реплики). Повторите после срока из заголовка `Retry-After` |

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

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

**`fields_partial` без `iblockId` не лечится повтором.** Предупреждение советует повторить запрос, но без `iblockId` каталога вариаций повтор вернёт тот же базовый набор. Сорок четыре базовых поля в этом ответе полные, недостаёт только свойств каталога и служебных полей — их даёт запрос с `?iblockId=`.

**Часть полей не приходит в списке по умолчанию.** Символьный код `code`, внешний код `xmlId`, сортировка `sort`, ставка `vatId`, габариты `width`, `height`, `length`, тексты, картинки, `quantityReserved`, `recurSchemeLength`, `recurSchemeType`, `trialPriceId` и свойства `propertyNNN` не возвращаются в ответе [`GET /v1/catalog-offers`](./list.md) без явного `?select=`. Перечислите нужные имена в `select`, чтобы получить их в списке. В ответе одной вариации [`GET /v1/catalog-offers/:id`](./get.md) они возвращаются всегда.

**Подписи называют запись товаром.** В `label` и `description` справочника вариация называется товаром — подписи совпадают с [Полями товара каталога](/docs/entities/catalog-products/fields). Поля `type` и `parentId` есть только у вариаций.

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

- [Список вариаций](/docs/entities/catalog-offers/list)
- [Создать вариацию](/docs/entities/catalog-offers/create)
- [Поиск вариаций](/docs/entities/catalog-offers/search)
- [Головные товары (SKU)](/docs/entities/catalog-skus)
- [Свойства товаров каталога](/docs/entities/catalog-product-properties)
- [Справочник API](/docs/api-reference)
