## SKU fields

`GET /v1/catalog-skus/fields`

Returns the parent product field reference with labels, types, read and write availability flags, descriptions and `enum` dictionaries where the value set is fixed, the list of fields for grouping in aggregation, and the operations available in a batch request.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|---------|
| `iblockId` (query) | number | no | Product catalog ID from [`GET /v1/catalogs`](/docs/entities/catalogs). With it, the reference is extended with the catalog properties `propertyNNN` and the `priceType` field. Without it, and also with the `iblockId` of an offer catalog or of a nonexistent catalog, the response has 24 static fields and the `fields_partial` warning in `meta.warnings` |

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/catalog-skus/fields?iblockId=25" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/catalog-skus/fields?iblockId=25" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

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

const { success, data } = await res.json()
console.log('Fields:', Object.keys(data.fields).length)
```

### JavaScript — OAuth application

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

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

## Response fields

`data.fields` is an object whose key matches the field name, and whose value contains the type, the write-access flags, a display label and — for fields with a fixed set of values — their dictionary. The set of keys is broken down in the table after the field list. `data.aggregatable` lists the fields for `groupBy` in [aggregation](./aggregate.md). `data.batch` lists the operations available in a [batch request](/docs/batch).

| Field | Type | RO | Description |
|------|-----|:--:|---------|
| `id` | number | yes | Parent product identifier |
| `name` | string | no | Parent product name. Required on create |
| `active` | boolean | no | Whether the product is active |
| `iblockId` | number | no¹ | Product catalog ID. List: [`GET /v1/catalogs`](/docs/entities/catalogs). Required on create, set on create only |
| `iblockSectionId` | number \| null | no | Primary catalog section ID. `null` — the product is not linked to a section. List: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) |
| `available` | boolean | yes | Whether the product is available for purchase. Computed by Bitrix24 |
| `bundle` | boolean | yes | Whether the product is a bundle. Computed by Bitrix24 |
| `dateActiveFrom` | datetime | no | Activity start date |
| `dateActiveTo` | datetime | no | Activity end date |
| `createdBy` | number | yes | ID of the user who created the product. List: [`GET /v1/users`](/docs/entities/users) |
| `modifiedBy` | number | yes | ID of the user who last modified the product. List: [`GET /v1/users`](/docs/entities/users) |
| `dateCreate` | datetime | yes | Creation date |
| `timestampX` | datetime | yes | Last modification date |
| `code` | string \| null | no | Product symbolic code. `null` if not set |
| `xmlId` | string | no | External code |
| `previewText` | string | no | Preview text |
| `detailText` | string | no | Detailed description |
| `previewTextType` | string | no | Preview text format: `text` or `html` |
| `detailTextType` | string | no | Detailed description format: `text` or `html` |
| `sort` | number | no | Sort order |
| `previewPicture` | object \| null | no | Preview image. Returned as an object `{ id, url, urlMachine }` or `null`. The field cannot be used for filtering or sorting |
| `detailPicture` | object \| null | no | Detail image, same format. The field cannot be used for filtering or sorting |
| `iblockSection` | object | no | Array of IDs of all product sections. Accepted on create and update. In the `get`, `create` and `update` responses it arrives as an array or `null`. It is not returned by the list and search endpoints and is not supported in `select` — the name triggers the `UNKNOWN_SELECT_FIELD` warning. List: [`GET /v1/catalog-sections`](/docs/entities/catalog-sections) |
| `type` | number | yes | Product type, computed by Bitrix24: `6` — a parent product without offers, `3` — with offers. The filter accepts one exact number, `3` or `6` |

¹ `iblockId` is writable on create only — in the reference it comes back with `readonly: false` and `createOnly: true`.

With the `iblockId` of a product catalog, `data.fields` gains the `priceType` field of type `char` and the catalog properties `propertyNNN` of type `productproperty`. Property names and types are returned by [`GET /v1/catalog-product-properties`](/docs/entities/catalog-product-properties).

Request headers do not switch the language of labels and descriptions. Enum values carry an English `label`.

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data.fields.<name>.type` | string | Field type: `number`, `string`, `boolean`, `datetime`, `object`. For catalog properties — `productproperty` |
| `data.fields.<name>.label` | string | Field label. For static fields — in English, for catalog properties it matches the field name |
| `data.fields.<name>.description` | string | Extended field description: what it is for, where to get the list of allowed values, write-time behavior |
| `data.fields.<name>.readonly` | boolean | `true` — the field is filled by the system and is not accepted on create or update |
| `data.fields.<name>.required` | boolean | `true` — the field is required on create (`name`, `iblockId`). The key is present only on such fields |
| `data.fields.<name>.createOnly` | boolean | `true` — the field is accepted on create only. On `PATCH` it is rejected with `READONLY_FIELD` (present on `iblockId`) |
| `data.fields.<name>.writeOnly` | boolean | `true` — the field is accepted on write and is not returned in the list and search (present on `iblockSection`) |
| `data.fields.<name>.notReturned` | boolean | `true` — the name is not supported in `select` (present on `iblockSection`) |
| `data.fields.<name>.nullable` | boolean | `true` — the field can come back as `null`. The key is present only on such fields |
| `data.fields.<name>.multiple` | boolean | `true` — the catalog property stores several values and arrives as an array. The key is present only on such properties |
| `data.fields.<name>.enum` | array | Dictionary of allowed values: an array of `{ value, label }`. The key is present on `previewTextType` and `detailTextType`. Send `value` — `label` is meant for display |
| `data.aggregatable` | string[] | Fields for `groupBy` in [aggregation](./aggregate.md): `iblockSectionId` |
| `data.batch` | string[] | Parent product operations available in a [batch request](/docs/batch): `create`, `update`, `delete` |
| `meta.warnings` | array | Returned when the request has no product catalog `iblockId`: an element `{ code: "fields_partial", message }` — the response has only the static fields |

## Response example

```json
{
  "success": true,
  "data": {
    "fields": {
      "id": {
        "type": "number",
        "readonly": true,
        "label": "Product identifier",
        "description": "Unique identifier of the catalog product."
      },
      "iblockId": {
        "type": "number",
        "readonly": false,
        "createOnly": true,
        "required": true,
        "label": "Catalog ID",
        "description": "Catalog the product belongs to. Available values: GET /v1/catalogs. Set on create only — changing it via PATCH is rejected, a product cannot be moved between catalogs."
      },
      "code": {
        "type": "string",
        "readonly": false,
        "nullable": true,
        "label": "Symbolic code",
        "description": "Symbolic product code; null when not set."
      },
      "iblockSection": {
        "type": "object",
        "readonly": false,
        "writeOnly": true,
        "notReturned": true,
        "label": "Catalog sections",
        "description": "Array of catalog section IDs the product belongs to. Accepted on create and update only — on read the primary section arrives as the scalar iblockSectionId. Available values: GET /v1/catalog-sections."
      },
      "previewTextType": {
        "type": "string",
        "readonly": false,
        "label": "Preview text format",
        "description": "Format of previewText.",
        "enum": [
          { "value": "text", "label": "Plain text" },
          { "value": "html", "label": "HTML" }
        ]
      },
      "type": {
        "type": "number",
        "readonly": true,
        "label": "Bitrix24 product type",
        "description": "Computed by Bitrix24. A newly created SKU starts as an empty SKU and changes type when offers are linked. Filtering accepts only exact type 3 or 6."
      },
      "property293": {
        "type": "productproperty",
        "readonly": false,
        "multiple": true,
        "label": "property293"
      }
    },
    "aggregatable": [
      "iblockSectionId"
    ],
    "batch": [
      "create",
      "update",
      "delete"
    ]
  }
}
```

The example is trimmed to seven fields — one each for the `readonly` flag, `createOnly` with `required`, `nullable`, the `writeOnly` + `notReturned` pair, the `enum` dictionary, the computed type, and a catalog property with `multiple`. The response returns all 24 static fields, and with the `iblockId` of a product catalog — also `priceType` and all catalog properties.

## Error response example

403 — the key does not have the `catalog` scope:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'catalog' scope",
    "hint": "This request needs the 'catalog' scope, which the calling key does not carry. Add 'catalog' to this key in the developer cabinet (or through the management API), then repeat the call.",
    "cause": "key_scope_missing",
    "requiredScope": "catalog",
    "keyScopes": ["task", "im"],
    "fix": { "action": "edit_key_scopes", "via": "cabinet" },
    "userMessage": "The app's API key lacks the “Product catalog” permission. You can add it in the key settings in the developer cabinet."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 403 | `SCOPE_DENIED` | The API key does not have the `catalog` scope |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not passed |
| 429 | `RATE_LIMITED` | Rate limit exceeded: 300 requests per minute per portal, all API keys of the portal share one limit. The exact value arrives in the `x-ratelimit-limit` header (the cap is divided across replicas). Retry after the delay in the `Retry-After` header |

Full list of common API errors — [Errors](/docs/errors).

## Known specifics

**Some fields are not returned in the list by default.** The symbolic code `code`, the external code `xmlId`, the sort order `sort`, the texts `previewText` and `detailText` with their formats, and the images are not returned in the `GET /v1/catalog-skus` response without an explicit `select`. List the names you need in `select` to get them in the list. In the single-product response `GET /v1/catalog-skus/:id` they are always returned.

## See also

- [List SKUs](/docs/entities/catalog-skus/list)
- [Create an SKU](/docs/entities/catalog-skus/create)
- [Search SKUs](/docs/entities/catalog-skus/search)
- [Aggregate SKUs](/docs/entities/catalog-skus/aggregate)
- [Catalog product properties](/docs/entities/catalog-product-properties)
- [API reference](/docs/api-reference)
