For AI agents: markdown of this page — /docs-content-en/entities/items/products-fields.md documentation index — /llms.txt
Item product fields
GET /v1/items/:entityTypeId/:id/products/fields
Returns a description of each field on an item's product rows: name, type, and whether the field is readable and writable.
The discount amount is called
discount— matching the data and the write contract. The previous namediscountSumremains a deprecated alias: it is still returned by this endpoint and still accepted on write, so code written against the old field list keeps working. Product rows themselves carry onlydiscount— migrate to it.
Use the entityTypeId field from GET /v1/smart-processes in the /v1/items/:entityTypeId path. The type record's internal id is a different identifier. For example, if a type is returned as { "id": 3, "entityTypeId": 174 }, the path starts with /v1/items/174. Use the returned value rather than assuming all type IDs start at 1030.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ParameterentityTypeId (path) |
Typenumber | Requiredyes | DescriptionSmart process type ID |
Parameterid (path) |
Typenumber | Requiredyes | DescriptionItem ID. Does not affect the response: the field dictionary is the same for every item |
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/items/156/741/products/fields" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/items/156/741/products/fields" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/items/156/741/products/fields', {
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
})
const { success, data } = await res.json()
console.log('Fields:', Object.keys(data).length)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/items/156/741/products/fields', {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata |
Typeobject | DescriptionProduct row field dictionary. The key is the field name, the value is its definition |
Fielddata.<field>.type |
Typestring | DescriptionValue type: integer, double, string, char |
Fielddata.<field>.isReadOnly |
Typeboolean | DescriptionRead-only: the field cannot be written |
Fielddata.<field>.isRequired |
Typeboolean | DescriptionRequired flag. false on every product-row field |
Fielddata.<field>.isImmutable |
Typeboolean | Descriptiontrue on ownerId and ownerType: the row owner is set by the request path. Absent on priceAccount and xmlId |
Fielddata.<field>.isMultiple |
Typeboolean | Descriptionfalse on product row fields. Absent on priceAccount and xmlId |
Fielddata.<field>.isDynamic |
Typeboolean | Descriptionfalse on product row fields. Absent on priceAccount and xmlId |
Fielddata.<field>.title |
Typestring | DescriptionField label. Absent on priceAccount and xmlId |
Fielddata.<field>.description |
Typestring | DescriptionField note. Present on id and discountSum |
Fieldmeta.warnings |
Typearray | DescriptionPresent only when Bitrix24 did not describe all of the fields. An item with the code fields_partial lists the fields whose definitions were derived without labels |
Product row fields described by data:
| Field | Type | RO | Required | Description |
|---|---|---|---|---|
Fieldid |
Typeinteger | ROyes | Required | DescriptionRow ID |
FieldproductId |
Typeinteger | RO | Required | DescriptionProduct ID. Catalog: GET /v1/products |
FieldproductName |
Typestring | RO | Required | DescriptionProduct name |
Fieldprice |
Typedouble | RO | Required | DescriptionPrice |
Fieldquantity |
Typedouble | RO | Required | DescriptionQuantity |
Fielddiscount |
Typedouble | RO | Required | DescriptionDiscount amount. Applied when discountTypeId is 1 |
FielddiscountSum |
Typedouble | RO | Required | DescriptionDeprecated alias of discount — accepted on write, absent from product rows |
FielddiscountRate |
Typedouble | RO | Required | DescriptionDiscount percentage. Applied when discountTypeId is 2 |
FielddiscountTypeId |
Typeinteger | RO | Required | DescriptionHow the discount is set: 1 — as an amount in discount, 2 — as a percentage in discountRate. Defaults to 2 |
FieldtaxRate |
Typedouble | RO | Required | DescriptionTax (%) |
FieldtaxIncluded |
Typechar | RO | Required | DescriptionTax included in price (Y/N) |
FieldpriceExclusive |
Typedouble | ROyes | Required | DescriptionPrice excluding tax, with discount |
FieldpriceNetto |
Typedouble | ROyes | Required | DescriptionNet price |
FieldpriceBrutto |
Typedouble | ROyes | Required | DescriptionGross price |
FieldmeasureCode |
Typeinteger | RO | Required | DescriptionUnit of measure code |
FieldmeasureName |
Typestring | ROyes | Required | DescriptionUnit of measure |
Fieldcustomized |
Typechar | ROyes | Required | DescriptionModified (Y/N) |
Fieldsort |
Typeinteger | RO | Required | DescriptionSort order |
Fieldtype |
Typeinteger | ROyes | Required | DescriptionProduct type — the same value as the product's type in GET /v1/catalog-products/:id: 1 — simple product, 3 — parent product with variations, 7 — service |
FieldstoreId |
Typeinteger | ROyes | Required | DescriptionWarehouse ID |
FieldtaxName |
Typestring | ROyes | Required | DescriptionTax name. Present only in the dictionary, never in product rows. In a write request body it is rejected with 400 INVALID_PARAMS |
FieldownerId |
Typeinteger | ROyes | Required | DescriptionOwner (item) ID |
FieldownerType |
Typestring | ROyes | Required | DescriptionOwner type |
FieldpriceAccount |
Typedouble | ROyes | Required | DescriptionPrice in the reporting currency |
FieldxmlId |
Typestring | ROyes | Required | DescriptionExternal code of the row |
Response example
The example shows 6 of the 25 fields (24 product-row field names plus the deprecated discountSum alias). The full list is in the table above.
{
"success": true,
"data": {
"id": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "ID", "description": "Row identity. Read-only as an attribute, and NOT a handle for editing: PUT /products does not preserve it — a row whose fields change comes back with a new id even if the previous one was sent. To edit a row and keep its id use PATCH /products/{rowId}." },
"ownerId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "Owner ID" },
"ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "isMultiple": false, "isDynamic": false, "title": "Owner type" },
"productId": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Product" },
"price": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Price" },
"priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Price excluding tax, with discount" }
}
}
About
id. Anidsupplied in theitemsarray ofPUT /v1/items/:entityTypeId/:id/productsdoes not guarantee that the row keeps its previous identifier: an unchanged row gets the sameideven without this field, while a changed row gets a new one. For targeted editing, usePATCH /v1/items/:entityTypeId/:id/products/:rowId.
Error response example
400 — entityTypeId in the path is not a positive integer:
{
"success": false,
"error": {
"code": "INVALID_DYNAMIC_PARAM",
"message": "Invalid entityTypeId: must be a positive integer"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | CodeINVALID_DYNAMIC_PARAM |
DescriptionentityTypeId is not a positive integer or is reserved (1, 2, 3, 4, 7, 31) |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe API key does not have the crm scope |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is not passed |
| HTTP401 | CodeTOKEN_MISSING |
DescriptionThe API key has no configured tokens |
| HTTP429 | CodeRATE_LIMITED |
DescriptionRate limit exceeded: 300 requests per minute per portal. All API keys of the portal share one limit. The current limit is returned in the x-ratelimit-limit header. Retry after the delay in the Retry-After header |
For the full list of common API errors, see Errors.