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

Add a product to an invoice

POST /v1/invoices/:id/products

Adds a single product row to an invoice. Unlike PUT /v1/invoices/:id/products, it does not replace existing rows.

Field names are validated. A field name that is not in the writable set is not dropped silently: the request is rejected with 400 INVALID_PARAMS and the error text lists the writable names. Read-only fields that appear in product-row responses — priceAccount, ownerId, storeId and others — are accepted and ignored, so an object read via GET can be sent back as is.

Parameters

Parameter Type Required Description
Parameterid (path) Typenumber Requiredyes DescriptionInvoice ID

Request fields (body)

Field Type Required Description
FieldproductId Typenumber Requiredno DescriptionCatalog product ID. If set without productName, the name is taken from the catalog. Catalog: GET /v1/products
FieldproductName Typestring Requiredno DescriptionProduct row name — for a free-form row with no catalog product. Specify at least one of productId and productName
Fieldprice Typenumber Requiredno DescriptionPrice per unit
Fieldquantity Typenumber Requiredno DescriptionQuantity
FielddiscountTypeId Typenumber Requiredno DescriptionHow the discount is set: 1 — as an amount in discount, 2 — as a percentage in discountRate. Defaults to 2
Fielddiscount Typenumber Requiredno DescriptionDiscount amount. Applied only when discountTypeId is 1
FielddiscountRate Typenumber Requiredno DescriptionDiscount percentage. Applied only when discountTypeId is 2
FieldtaxRate Typenumber Requiredno DescriptionTax rate (%)
FieldtaxIncluded Typeboolean Requiredno DescriptionTax included in the price

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/invoices/58/products" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "productId": 1, "price": 25000, "quantity": 2 }'

curl — OAuth application

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/invoices/58/products" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "productId": 1, "price": 25000, "quantity": 2 }'

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/invoices/58/products', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }),
})

const { success, data } = await res.json()
console.log('Row ID:', data.id)

JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/invoices/58/products', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ productId: 1, price: 25000, quantity: 2 }),
})

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

Response fields

Field Type Description
Fielddata Typeobject DescriptionThe created product row in full, HTTP status 201. Field set — Product fields

Response example

Key fields shown. Full list — Product fields.

JSON
{
  "success": true,
  "data": {
    "id": 1465,
    "productId": 1,
    "productName": "Server equipment",
    "price": 25000,
    "quantity": 2,
    "discount": 0,
    "discountTypeId": 2,
    "taxIncluded": false
  }
}

Error response example

404 — invoice not found:

JSON
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Item not found"
  }
}

Errors

HTTP Code Description
HTTP400 CodeINVALID_PARAMS DescriptionThe body contains a field name that is not among the writable fields — see Product fields
HTTP404 CodeENTITY_NOT_FOUND DescriptionInvoice not found
HTTP403 CodeSCOPE_DENIED DescriptionAPI key lacks the crm scope
HTTP401 CodeTOKEN_MISSING DescriptionAPI key has no configured tokens

Full list of common API errors — Errors.

Known specifics

An amount discount requires discountTypeId: 1. The discount type defaults to 2, a percentage, and in that mode the discount field is not stored: the row is created with discount: 0 and no error is raised. To set a discount as an amount, send discountTypeId: 1 together with discount; to set it as a percentage, send discountRate with type 2.

See also