For AI agents: markdown of this page — /docs-content-en/entities/invoices/products-fields.md documentation index — /llms.txt

Invoice product fields

GET /v1/invoices/:id/products/fields

Returns descriptions of the fields on invoice product rows: names, types, and whether each field is readable and writable.

The discount amount is called discount — matching the data and the write contract. The previous name discountSum remains 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 only discount — migrate to it.

Parameters

Parameter Type Req. Description
id (path) number yes Invoice ID

Examples

curl — personal key

Terminal
curl "https://vibecode.bitrix24.com/v1/invoices/741/products/fields" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth application

Terminal
curl "https://vibecode.bitrix24.com/v1/invoices/741/products/fields" \
  -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/invoices/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

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/invoices/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 RO Req. Description
id integer yes Row ID
productId integer yes Product ID. Catalog: GET /v1/products
productName string Product name
price double Price
quantity double Quantity
discount double Discount amount. Applied when discountTypeId is 1
discountSum double Deprecated alias of discount — accepted on write, absent from product rows
discountRate double Discount percentage. Applied when discountTypeId is 2
discountTypeId integer How the discount is set: 1 — as an amount in discount, 2 — as a percentage in discountRate. Defaults to 2
taxRate double Tax (%)
taxName string yes Tax name
taxIncluded char Tax included in the price (Y/N)
priceExclusive double yes Price excluding tax, with discount
priceNetto double yes Net price
priceBrutto double yes Gross price
measureCode integer Unit of measure code
measureName string yes Unit of measure
customized char yes Modified (Y/N)
sort integer Sort order
type integer yes Type
storeId integer yes Warehouse ID
ownerId integer yes Owner (invoice) ID
ownerType string yes Owner type
priceAccount double yes Price in the reporting currency
xmlId string yes External code of the row

Response example

JSON
{
  "success": true,
  "data": {
    "id": { "type": "integer", "isRequired": false, "isReadOnly": true, "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, "title": "Owner ID" },
    "ownerType": { "type": "string", "isRequired": false, "isReadOnly": true, "isImmutable": true, "title": "Owner type" },
    "productId": { "type": "integer", "isRequired": true, "isReadOnly": false, "title": "Product" },
    "productName": { "type": "string", "isRequired": false, "isReadOnly": false, "title": "Product name" },
    "price": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Price" },
    "priceExclusive": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "Price excluding tax, with discount" },
    "priceNetto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_NETTO" },
    "priceBrutto": { "type": "double", "isRequired": false, "isReadOnly": true, "title": "PRICE_BRUTTO" },
    "quantity": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Quantity" },
    "discountTypeId": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Discount type" },
    "discountRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Discount value" },
    "discount": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Discount amount" },
    "discountSum": { "type": "double", "isRequired": false, "isReadOnly": 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`." },
    "taxRate": { "type": "double", "isRequired": false, "isReadOnly": false, "title": "Tax" },
    "taxName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "TAX_NAME" },
    "taxIncluded": { "type": "char", "isRequired": false, "isReadOnly": false, "title": "Tax included in the price" },
    "customized": { "type": "char", "isRequired": false, "isReadOnly": true, "title": "Modified" },
    "measureCode": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Unit of measure code" },
    "measureName": { "type": "string", "isRequired": false, "isReadOnly": true, "title": "Unit of measure" },
    "sort": { "type": "integer", "isRequired": false, "isReadOnly": false, "title": "Sort order" },
    "type": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "TYPE" },
    "storeId": { "type": "integer", "isRequired": false, "isReadOnly": true, "title": "STORE_ID" },
    "priceAccount": { "type": "double", "isRequired": false, "isReadOnly": true },
    "xmlId": { "type": "string", "isRequired": false, "isReadOnly": true }
  }
}

About id. An id supplied in PUT /v1/invoices/:id/products items does not guarantee the row's previous identifier: an unchanged row gets the same id even without this field, while a changed row gets a new one. For targeted editing, use PATCH /v1/invoices/:id/products/:rowId.

The schema is the same for every invoice. The response does not depend on the id in the URL: passing the ID of a nonexistent invoice returns the same schema and the same 200, not a refusal. This call cannot be used to check that an invoice exists — GET /v1/invoices/:id is there for that.

Error response example

403 — the key lacks the required scope:

JSON
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'crm' scope"
  }
}

Errors

HTTP Code Description
403 SCOPE_DENIED API key lacks the crm scope
401 TOKEN_MISSING API key has no configured tokens
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.

See also