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

Search CRM products

POST /v1/products/search

Search catalog products with filters and auto-pagination. Parameters are passed in the request body — this is more convenient for compound filters made up of several conditions and for building requests programmatically. For lists of up to 5000 records, GET /v1/products with a filter in query parameters also works.

Request fields (body)

Parameter Type Default Description
filter object Only exact match and $in (IN set) on the fields id, name, code, xmlId, active, sectionId, sort, description. Operators (>, >=, <, <=, !, %, $ne, $contains, $nin) and filtering by other fields (price, currency) are not supported — 400 UNSUPPORTED_FILTER is returned.
Filtering syntax. Example: { "sectionId": 19, "active": true }
limit number 50 Number of records (up to 5000)
offset number 0 Skip N records
order object Sorting by the fields id, name, sort: { "sort": "desc" }. The fields price and currency do not support sorting
select string[] Field selection: ["id", "name", "price"]. A custom catalog property is requested by its own name: ["id", "name", "PROPERTY_301"]. Property names are listed in CRM product fields

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/products/search" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": { "active": true },
    "limit": 20,
    "order": { "sort": "desc" }
  }'

curl — OAuth application

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/products/search" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": { "active": true },
    "limit": 20,
    "order": { "sort": "desc" }
  }'

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/products/search', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    filter: { active: true },
    limit: 20,
    order: { sort: 'desc' },
  }),
})

const { success, data, meta } = await res.json()
console.log('Found:', meta.total)

JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/products/search', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    filter: { active: true },
    limit: 20,
    order: { sort: 'desc' },
  }),
})

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

Other scenarios

Products from a single catalog section:

JSON
{ "filter": { "sectionId": 19 } }

Several products by identifiers via $in:

JSON
{ "filter": { "id": { "$in": [6967, 533] } } }

Response fields

Field Type Description
success boolean Always true on success
data array Array of products (all fields — see CRM product fields)
meta.total number Total number of records matching the filter
meta.hasMore boolean Whether there are more records beyond limit
meta.durationMs number Request duration in milliseconds

The meta fields sit next to data, not inside it. Pages must be walked by meta.hasMore: a data length equal to limit does not rule out the last page.

The card URL of any product from the data array is built from catalogId and id: https://<portal>.bitrix24.com/shop/catalog/<catalogId>/product/<id>/. <portal> is the Bitrix24 portal domain. Access is restricted by the employee's permissions in Bitrix24.

Response example

JSON
{
  "success": true,
  "data": [
    {
      "id": 6967,
      "name": "Master product",
      "code": "product_sku",
      "active": true,
      "sort": 100,
      "xmlId": "6967",
      "catalogId": 25,
      "sectionId": null,
      "price": 100,
      "currency": "USD",
      "vatId": null,
      "vatIncluded": false,
      "createdAt": "2025-05-12T09:03:15.000Z",
      "updatedAt": "2025-05-12T09:05:27.000Z"
    },
    {
      "id": 6969,
      "name": "Service",
      "code": "service",
      "active": true,
      "catalogId": 25,
      "price": 250,
      "currency": "USD",
      "vatId": 1,
      "vatIncluded": true,
      "createdAt": "2025-05-12T09:04:01.000Z",
      "updatedAt": "2025-05-12T09:04:01.000Z"
    }
  ],
  "meta": { "total": 19, "hasMore": true, "durationMs": 2509 }
}

Error response example

400 — an operator or unsupported field in the filter:

JSON
{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_FILTER",
    "message": "UNSUPPORTED_FILTER: operators are not supported on 'products' (near 'price'). Its Bitrix24 method (crm.product.list) filters by exact match only — operators are silently ignored by Bitrix24. Use exact match (field: value) or $in (field: {$in: [...]}) on: id, name, code, xmlId, active, sectionId, sort, description."
  }
}

Errors

HTTP Code Description
400 UNSUPPORTED_FILTER An operator or unsupported field in the filter. Filter by exact match or $in on id, name, code, xmlId, active, sectionId, sort, description
400 INVALID_FILTER Error while parsing the filter
400 UNKNOWN_SELECT_FIELD select carries a name the product does not have. The message lists the allowed names after the word Available
400 SELECT_FIELD_NOT_RETURNED select carries a name that CRM product fields shows with notReturned: truecurrencyId, for example. Drop it from select
403 SCOPE_DENIED The API key lacks the crm 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.

Known specifics

Auto-pagination. When limit > 50, the request is automatically split into several calls to Bitrix24, up to 5000 records per call. When more records match the filter, meta.hasMore equals true — increase offset for the next batch.

Catalog properties arrive only when named. Without select, the data array contains the base product fields. Name every property you need in select["id", "name", "PROPERTY_295"]. A select containing an asterisk does not return them.

See also