For AI agents: markdown of this page — /docs-content-en/entities/deals/products-fields.md documentation index — /llms.txt
Deal product fields
GET /v1/deals/:id/products/fields
Returns descriptions of the fields on deal product rows: names, types, and whether each field is readable and writable.
The discount amount is called
discount— the same name as in the row data and on write. 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.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Parameterid (path) |
Typenumber | Requiredyes | DescriptionDeal ID. Does not affect the response: the field dictionary is the same for every deal |
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/deals/741/products/fields" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/deals/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/deals/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/deals/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: a write accepts a row that carries at least one writable 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 described some of the fields but not all. 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. A row without productId is created with productId set to 0 and the name from productName — see Add a product |
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. In product rows the field is returned as true or false, even though the dictionary gives its type as char. You can write any of the values true, false, 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 (deal) 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
{
"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" },
"productName": { "type": "string", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Product name" },
"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" },
"priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "PRICE_NETTO" },
"priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "PRICE_BRUTTO" },
"quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Quantity" },
"discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Discount type" },
"discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Discount value" },
"discount": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Discount amount" },
"taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Tax" },
"taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Tax included in price" },
"customized": { "type": "char", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Modified" },
"measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Unit of measure code" },
"measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Unit of measure" },
"sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Sort order" },
"type": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "TYPE" },
"storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "STORE_ID" },
"taxName": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "TAX_NAME" },
"priceAccount": { "type": "double", "isReadOnly": true, "isRequired": false },
"xmlId": { "type": "string", "isReadOnly": true, "isRequired": false },
"discountSum": { "type": "double", "isRequired": false, "isReadOnly": false, "isImmutable": false, "isMultiple": false, "isDynamic": false, "title": "Discount amount", "description": "Deprecated alias of `discount`; kept so clients written against the previous field list keep working. Accepted on write, never present in row data — migrate to `discount`." }
}
}
About
id. Anidsupplied inPUT /v1/deals/:id/productsitems does not guarantee the row's previous identifier: an unchanged row gets the sameideven without this field, while a changed row gets a new one. For targeted editing, usePATCH /v1/deals/:id/products/:rowId.
Error response example
401 — API key not passed:
{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "API key required. Pass via X-Api-Key header."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP403 | CodeSCOPE_DENIED |
DescriptionAPI key lacks the crm scope |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is not passed |
| HTTP401 | CodeTOKEN_MISSING |
DescriptionAPI 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.