[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-entities\u002Fbasket-items":3,"docs-tabs-entities\u002Fbasket-items":6},{"content":4,"lastmod":5},"# Позиции корзины\n\nУправление товарными позициями в заказах: создание, получение, обновление, удаление, поиск, агрегация. Позиция корзины — отдельная сущность, привязанная к заказу по полю `orderId`. У одного заказа может быть несколько позиций — по одной на каждый купленный товар.\n\nБитрикс24 API: `sale.basketitem.*`\nСкоуп: `sale`\n\n## Операции\n\n- [Добавить позицию](.\u002Fbasket-items\u002Fcreate.md) — `POST \u002Fv1\u002Fbasket-items`\n- [Список позиций](.\u002Fbasket-items\u002Flist.md) — `GET \u002Fv1\u002Fbasket-items`\n- [Получить позицию](.\u002Fbasket-items\u002Fget.md) — `GET \u002Fv1\u002Fbasket-items\u002F:id`\n- [Обновить позицию](.\u002Fbasket-items\u002Fupdate.md) — `PATCH \u002Fv1\u002Fbasket-items\u002F:id`\n- [Удалить позицию](.\u002Fbasket-items\u002Fdelete.md) — `DELETE \u002Fv1\u002Fbasket-items\u002F:id`\n- [Поиск позиций](.\u002Fbasket-items\u002Fsearch.md) — `POST \u002Fv1\u002Fbasket-items\u002Fsearch`\n- [Поля позиции](.\u002Fbasket-items\u002Ffields.md) — `GET \u002Fv1\u002Fbasket-items\u002Ffields`\n- [Агрегация позиций](.\u002Fbasket-items\u002Faggregate.md) — `POST \u002Fv1\u002Fbasket-items\u002Faggregate`\n\n## Ключевые поля\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `id` | number | Идентификатор позиции (только чтение) |\n| `orderId` | number | Обязателен при создании. Идентификатор заказа. Источник: [`GET \u002Fv1\u002Forders`](.\u002Forders\u002Flist.md) |\n| `productId` | number | Обязателен при создании. Идентификатор товара в каталоге. `0` — виртуальная позиция без привязки к каталогу. Источник: [`GET \u002Fv1\u002Fcatalog-products`](\u002Fdocs\u002Fentities\u002Fcatalog-products) |\n| `name` | string | Название позиции. Для каталожного товара заполняется из карточки |\n| `price` | number | Цена за единицу |\n| `basePrice` | number | Базовая цена до скидки |\n| `discountPrice` | number | Размер скидки за единицу |\n| `quantity` | number | Обязательно при создании. Количество |\n| `currency` | string | Обязательна при создании. Валюта позиции. Список: [`GET \u002Fv1\u002Fcurrencies`](\u002Fdocs\u002Fentities\u002Fcurrencies) |\n| `vatRate` | number | Ставка НДС в долях единицы (`0.20` = 20%) |\n| `vatIncluded` | boolean | Включён ли НДС в цену |\n| `weight` | number | Вес в граммах |\n| `dimensions` | string | Габариты в формате сериализации PHP |\n| `measureCode` | number | Код единицы измерения (`796` = шт, `163` = г, `006` = м и др.) |\n| `measureName` | string | Название единицы измерения |\n| `xmlId` | string | Внешний идентификатор позиции |\n\nПолный список полей — [`GET \u002Fv1\u002Fbasket-items\u002Ffields`](.\u002Fbasket-items\u002Ffields.md).\n\n## Что нужно знать перед работой\n\n1. **Тело запроса плоское.** При создании и обновлении передавайте поля прямо в корне JSON: `{\"orderId\": 33, \"productId\": 119, ...}`. Обёртка `fields` не нужна.\n2. **Обязательные поля при создании.** Для добавления позиции нужны `orderId`, `productId`, `currency` и `quantity`. Поле `orderId` ссылается на существующий заказ — сначала вызовите [`POST \u002Fv1\u002Forders`](.\u002Forders\u002Fcreate.md). Поле `productId` привязывает позицию к товару каталога. Значение `productId: 0` создаёт виртуальную позицию без привязки к каталогу — для неё `name` и `price` задаются вручную.\n3. **`vatRate` хранится в долях единицы.** Для НДС 20% передавайте `0.20`, не `20`. Для 10% — `0.10`. Для без НДС — `0` или не передавать.\n4. **Цены передавайте согласованно.** `price` — итоговая цена за единицу с учётом скидки, `basePrice` — до скидки, `discountPrice` — размер скидки. Битрикс24 не пересчитывает эти поля между собой автоматически. Передайте `customPrice: true`, чтобы цена позиции не обновлялась при изменении цены товара в каталоге.\n\n## Связанные сущности\n\n| Сущность | Эндпоинт | Назначение |\n|----------|----------|-----------|\n| Заказы | [`GET \u002Fv1\u002Forders\u002F:id`](.\u002Forders\u002Fget.md) | Родительский заказ — `orderId` указывается при создании позиции. |\n| Товары каталога | [`GET \u002Fv1\u002Fcatalog-products`](\u002Fdocs\u002Fentities\u002Fcatalog-products) | Источник `productId` для привязки позиции к товару. |\n| Оплаты | [`GET \u002Fv1\u002Fpayments?filter[orderId]=:id`](.\u002Fpayments.md) | Платежи по тому же заказу. |\n\n## Типичный сценарий\n\nДобавление товаров в заказ из внешней системы:\n\n1. Создать заказ: [`POST \u002Fv1\u002Forders`](.\u002Forders\u002Fcreate.md) — получить `orderId`.\n2. Найти товары в каталоге: [`GET \u002Fv1\u002Fcatalog-products`](\u002Fdocs\u002Fentities\u002Fcatalog-products) — получить `productId` для каждой позиции.\n3. Добавить позиции: цикл [`POST \u002Fv1\u002Fbasket-items`](.\u002Fbasket-items\u002Fcreate.md) с `orderId`, `productId`, `quantity`, `price`, `currency`, `vatRate`.\n4. Зарегистрировать оплату: [`POST \u002Fv1\u002Fpayments`](.\u002Fpayments\u002Fcreate.md).\n\n## Лимиты\n\n| Лимит | Значение |\n|-------|----------|\n| Максимум записей на запрос | 5000 (`limit ≤ 5000`) |\n| Автоматическая пагинация | включается при `limit > 50` |\n| `offset` на больших выборках | рекомендуется `limit ≤ 500` при `offset ≥ 2500` |\n| Batch-запросы | до 50 операций в [`POST \u002Fv1\u002Fbatch`](\u002Fdocs\u002Fbatch) |\n| Частота запросов | общая для API Вайбкод — см. [Лимиты и оптимизация](\u002Fdocs\u002Foptimization) |\n\n## Смотрите также\n\n- [Поля позиции](.\u002Fbasket-items\u002Ffields.md)\n- [Заказы](.\u002Forders.md)\n- [Оплаты](.\u002Fpayments.md)\n- [Товары каталога](\u002Fdocs\u002Fentities\u002Fcatalog-products)\n- [Entity API](\u002Fdocs\u002Fentity-api)\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering)\n- [Batch](\u002Fdocs\u002Fbatch)\n- [Справочник сущностей](\u002Fdocs\u002Fentities-index)\n","2026-06-29",{"basket-items\u002Fcreate.md":7,"basket-items\u002Flist.md":8,"basket-items\u002Fget.md":9,"basket-items\u002Fupdate.md":10,"basket-items\u002Fdelete.md":11,"basket-items\u002Fsearch.md":12,"basket-items\u002Ffields.md":13,"basket-items\u002Faggregate.md":14},"\n## Добавить позицию в корзину\n\n`POST \u002Fv1\u002Fbasket-items`\n\nДобавляет товарную позицию в существующий заказ. Позиция ссылается на товар каталога через `productId` либо создаётся виртуальной при `productId: 0`. Тело запроса плоское — без обёртки `fields`.\n\n## Поля запроса (тело)\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `orderId` | number | да | Идентификатор заказа. Источник: [`GET \u002Fv1\u002Forders`](..\u002Forders\u002Flist.md) |\n| `productId` | number | да | Идентификатор товара в каталоге. Источник: [`GET \u002Fv1\u002Fcatalog-products`](\u002Fdocs\u002Fentities\u002Fcatalog-products). Значение `0` создаёт виртуальную позицию без привязки к каталогу |\n| `currency` | string | да | Валюта позиции. Список: [`GET \u002Fv1\u002Fcurrencies`](\u002Fdocs\u002Fentities\u002Fcurrencies) |\n| `quantity` | number | да | Количество |\n| `name` | string | нет | Название позиции. При `productId > 0` подставляется из карточки товара — переданное значение на создании не сохраняется. При `productId: 0` сохраняется как передано |\n| `price` | number | нет | Цена за единицу. Для виртуальной позиции задаётся вручную. Передача `price` включает `customPrice` |\n| `basePrice` | number | нет | Базовая цена до скидки. По умолчанию равна `price` |\n| `discountPrice` | number | нет | Размер скидки за единицу. По умолчанию `0` |\n| `customPrice` | boolean | нет | Защита цены от автопересчёта при изменении товара в каталоге. При передаче `price` выставляется в `true`. По умолчанию `false` |\n| `vatRate` | number | нет | Ставка НДС в долях единицы. `0.20` = 20%, `0.10` = 10%, `0` — без НДС |\n| `vatIncluded` | boolean | нет | Включён ли НДС в цену. По умолчанию `true` |\n| `weight` | number | нет | Вес единицы в граммах |\n| `measureCode` | number | нет | Код единицы измерения. `796` — шт, `163` — г, `006` — м |\n| `productXmlId` | string | нет | Внешний идентификатор товара. Для виртуальной позиции задаётся вручную |\n| `catalogXmlId` | string | нет | Внешний идентификатор каталога. Для виртуальной позиции задаётся вручную |\n| `xmlId` | string | нет | Внешний идентификатор позиции |\n\n## Примеры\n\nПримеры ниже создают виртуальную позицию `productId: 0` — для неё `name` сохраняется как передано.\n\n### curl — личный ключ\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"orderId\": 1,\n    \"productId\": 0,\n    \"currency\": \"RUB\",\n    \"quantity\": 1,\n    \"name\": \"Подарочная упаковка\"\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"orderId\": 1,\n    \"productId\": 0,\n    \"currency\": \"RUB\",\n    \"quantity\": 1,\n    \"name\": \"Подарочная упаковка\"\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    orderId: 1,\n    productId: 0,\n    currency: 'RUB',\n    quantity: 1,\n    name: 'Подарочная упаковка',\n  }),\n})\n\nconst { success, data } = await res.json()\nconsole.log('Basket item ID:', data.id)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    orderId: 1,\n    productId: 0,\n    currency: 'RUB',\n    quantity: 1,\n    name: 'Подарочная упаковка',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\nКаталожная позиция создаётся передачей `productId` товара — `name`, `price` и единица измерения заполнятся из его карточки:\n\n```json\n{\n  \"orderId\": 1,\n  \"productId\": 119,\n  \"currency\": \"RUB\",\n  \"quantity\": 2\n}\n```\n\n## Поля ответа\n\nВозвращается полный объект созданной позиции.\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `id` | number | Идентификатор созданной позиции |\n| `name` | string | Название. Для каталожного товара — из карточки, для виртуальной позиции — как передано |\n| `price` | number | Цена за единицу |\n| `customPrice` | boolean | `true`, если цена задана вручную через `price` |\n| `productXmlId` | string \\| null | Внешний идентификатор товара. `null` у виртуальной позиции без переданного значения |\n| `catalogXmlId` | string \\| null | Внешний идентификатор каталога. `null` у виртуальной позиции без переданного значения |\n| `dateInsert` | datetime | Дата создания |\n\nПолный набор полей — [`GET \u002Fv1\u002Fbasket-items\u002Ffields`](.\u002Ffields.md).\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 1021,\n    \"orderId\": 1,\n    \"productId\": 0,\n    \"name\": \"Подарочная упаковка\",\n    \"price\": 0,\n    \"basePrice\": 0,\n    \"discountPrice\": 0,\n    \"customPrice\": false,\n    \"currency\": \"RUB\",\n    \"quantity\": 1,\n    \"sort\": 100,\n    \"weight\": null,\n    \"dimensions\": null,\n    \"measureCode\": null,\n    \"measureName\": null,\n    \"canBuy\": true,\n    \"vatRate\": null,\n    \"vatIncluded\": true,\n    \"xmlId\": \"bx_6a3e475a2d55c\",\n    \"productXmlId\": null,\n    \"catalogXmlId\": null,\n    \"dateInsert\": \"2026-06-26T08:33:14.000Z\",\n    \"dateUpdate\": \"2026-06-26T08:33:14.000Z\"\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n422 — не переданы обязательные поля:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"BITRIX_ERROR\",\n    \"message\": \"Required fields: orderId, productId, currency, quantity\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 422 | `BITRIX_ERROR` | Не переданы обязательные поля — сообщение содержит их список |\n| 422 | `BITRIX_ERROR` | Несуществующий `orderId` или `productId` — позиция не сохранена |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Имя каталожного товара берётся из карточки.** При `productId > 0` поля `name`, `productXmlId`, `catalogXmlId`, `measureCode`, `measureName` заполняются из карточки товара. Переданное в запросе `name` на создании не сохраняется. Чтобы задать каталожной позиции произвольное имя, обновите её после создания через [`PATCH \u002Fv1\u002Fbasket-items\u002F:id`](.\u002Fupdate.md).\n\n**Виртуальная позиция.** При `productId: 0` позиция не привязана к каталогу. Поля `name`, `price`, `productXmlId`, `catalogXmlId` задаются вручную в запросе и сохраняются как переданы.\n\n**Ручная цена включает `customPrice`.** Если передать `price`, в ответе `customPrice` становится `true` — цена позиции не пересчитывается при изменении цены товара в каталоге. Без `price` остаётся `false`.\n\n**Несколько позиций для одного товара.** Можно добавить одну и ту же `productId` в заказ несколькими позициями — Битрикс24 не объединяет их. Чтобы увеличить количество существующей позиции, используйте [`PATCH \u002Fv1\u002Fbasket-items\u002F:id`](.\u002Fupdate.md) с `quantity`.\n\n## Смотрите также\n\n- [Список позиций](.\u002Flist.md)\n- [Получить позицию](.\u002Fget.md)\n- [Обновить позицию](.\u002Fupdate.md)\n- [Поля позиции](.\u002Ffields.md)\n- [Заказ](..\u002Forders\u002Fget.md)\n- [Товары каталога](\u002Fdocs\u002Fentities\u002Fcatalog-products)\n- [Batch](\u002Fdocs\u002Fbatch)\n","\n## Список позиций корзины\n\n`GET \u002Fv1\u002Fbasket-items`\n\nВозвращает список позиций корзины с поддержкой фильтрации и автоматической пагинации.\n\n## Параметры\n\n| Параметр | Тип | По умолч. | Описание |\n|----------|-----|-----------|---------|\n| `limit` | number | `50` | Количество записей (до 5000). При `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 |\n| `offset` | number | `0` | Пропустить N записей. При `offset ≥ 2500` рекомендуется `limit ≤ 500` |\n| `select` | string | — | Выборка полей: `?select=id,orderId,name,quantity,price` |\n| `order` | object | — | Сортировка: `?order[id]=desc` |\n| `filter` | object | — | Фильтрация по ключевым полям позиции.\u003Cbr>[Синтаксис фильтрации](\u002Fdocs\u002Ffiltering). Пример: `?filter[orderId]=33` |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items?limit=10&filter[orderId]=33\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items?limit=10&filter[orderId]=33\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items?limit=10&filter[orderId]=33', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data, meta } = await res.json()\nconsole.log(`Позиций в заказе: ${meta.total}`)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items?limit=10&filter[orderId]=33', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data, meta } = await res.json()\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data` | array | Массив позиций корзины |\n| `meta.total` | number | Общее количество записей, соответствующих фильтру |\n| `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 9,\n      \"orderId\": 33,\n      \"productId\": 119,\n      \"name\": \"Домашние Тапочки Любимый Спорт\",\n      \"price\": 470,\n      \"basePrice\": 470,\n      \"discountPrice\": 0,\n      \"currency\": \"RUB\",\n      \"quantity\": 1,\n      \"weight\": 0,\n      \"vatRate\": 0,\n      \"vatIncluded\": true,\n      \"measureCode\": 796,\n      \"measureName\": \"шт\",\n      \"xmlId\": \"bx_5fc9f8c57fe6c\",\n      \"productXmlId\": \"1000000475\",\n      \"catalogXmlId\": \"FUTURE-1C-CATALOG\",\n      \"canBuy\": true,\n      \"dateInsert\": \"2020-12-04T07:52:21.000Z\",\n      \"dateUpdate\": \"2022-11-02T05:10:13.000Z\"\n    }\n  ],\n  \"meta\": {\n    \"total\": 1,\n    \"hasMore\": false\n  }\n}\n```\n\nПоказаны основные поля. Полный ответ позиции — см. [`GET \u002Fv1\u002Fbasket-items\u002F:id`](.\u002Fget.md).\n\n## Пример ответа при ошибке\n\n400 — фильтр по несуществующему полю:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"UNKNOWN_FILTER_FIELD\",\n    \"message\": \"Unknown filter field 'foo' for entity 'basket-items'. Available: …\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Автоматическая пагинация:** при `limit > 50` Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе.\n\n**Свободные позиции без заказа.** Часть позиций в `data[]` может иметь `orderId: null` — это позиции в незавершённых корзинах покупателей, ещё не оформленных в заказ. Чтобы исключить их, добавьте `filter[orderId][!]=null` или фильтр по конкретному `orderId`.\n\n## Смотрите также\n\n- [Поиск позиций](.\u002Fsearch.md)\n- [Получить позицию](.\u002Fget.md)\n- [Добавить позицию](.\u002Fcreate.md)\n- [Заказ](..\u002Forders\u002Fget.md)\n- [Товары каталога](\u002Fdocs\u002Fentities\u002Fcatalog-products)\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering)\n- [Entity API](\u002Fdocs\u002Fentity-api)\n- [Batch](\u002Fdocs\u002Fbatch)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n","\n## Получить позицию корзины\n\n`GET \u002Fv1\u002Fbasket-items\u002F:id`\n\nВозвращает одну позицию корзины по идентификатору со всеми полями.\n\n## Параметры\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `id` (path) | number | да | Идентификатор позиции |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { success, data } = await res.json()\nconsole.log('Позиция:', data.name, '×', data.quantity, '=', data.price * data.quantity, data.currency)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { success, data } = await res.json()\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `id` | number | Идентификатор позиции |\n| `orderId` | number \\| null | Идентификатор заказа. `null` у свободных позиций без заказа |\n| `productId` | number | Идентификатор товара в каталоге |\n| `name` | string | Название товара |\n| `price` | number | Цена за единицу |\n| `basePrice` | number | Базовая цена до скидки |\n| `discountPrice` | number | Размер скидки за единицу |\n| `currency` | string | Валюта |\n| `quantity` | number | Количество |\n| `sort` | number | Порядок позиции в корзине |\n| `weight` | number \\| null | Вес в граммах. `null` у виртуальных позиций с `productId: 0` |\n| `vatRate` | number \\| null | Ставка НДС в долях единицы. `null` у виртуальных позиций с `productId: 0` |\n| `vatIncluded` | boolean | Включён ли НДС в цену |\n| `customPrice` | boolean | Защита цены от автопересчёта при изменении товара в каталоге |\n| `canBuy` | boolean | Доступен ли товар к покупке |\n| `barcodeMulti` | boolean | Позиция учитывается по нескольким штрихкодам |\n| `measureCode` | number \\| null | Код единицы измерения. `null` у виртуальных позиций с `productId: 0` |\n| `measureName` | string \\| null | Название единицы измерения. `null` у виртуальных позиций с `productId: 0` |\n| `dimensions` | string \\| null | Габариты в формате сериализации PHP. `null` у виртуальных позиций с `productId: 0` |\n| `xmlId` | string | Внешний идентификатор позиции |\n| `productXmlId` | string \\| null | Внешний идентификатор товара в каталоге. `null` у виртуальных позиций с `productId: 0` |\n| `catalogXmlId` | string \\| null | Внешний идентификатор каталога. `null` у виртуальных позиций с `productId: 0` |\n| `type` | string \\| null | Тип позиции. На живых порталах всегда `null` |\n| `properties` | array | Свойства позиции. Каждый элемент: `{basketId, code, id, name, sort, value, xmlId}` |\n| `reservations` | array | Резервы позиции на складах |\n| `dateInsert` | datetime | Дата создания |\n| `dateUpdate` | datetime | Дата последнего изменения |\n\nПолный список полей — [`GET \u002Fv1\u002Fbasket-items\u002Ffields`](.\u002Ffields.md).\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 9,\n    \"orderId\": 33,\n    \"productId\": 119,\n    \"name\": \"Домашние Тапочки Любимый Спорт\",\n    \"price\": 470,\n    \"basePrice\": 470,\n    \"discountPrice\": 0,\n    \"currency\": \"RUB\",\n    \"quantity\": 1,\n    \"weight\": 0,\n    \"vatRate\": 0,\n    \"vatIncluded\": true,\n    \"customPrice\": false,\n    \"canBuy\": true,\n    \"barcodeMulti\": false,\n    \"measureCode\": 796,\n    \"measureName\": \"шт\",\n    \"dimensions\": \"a:3:{s:5:\\\"WIDTH\\\";N;s:6:\\\"HEIGHT\\\";N;s:6:\\\"LENGTH\\\";N;}\",\n    \"xmlId\": \"bx_5fc9f8c57fe6c\",\n    \"productXmlId\": \"1000000475\",\n    \"catalogXmlId\": \"FUTURE-1C-CATALOG\",\n    \"type\": null,\n    \"sort\": 200,\n    \"properties\": [\n      {\n        \"id\": 17,\n        \"basketId\": 9,\n        \"code\": \"CATALOG.XML_ID\",\n        \"name\": \"Catalog XML_ID\",\n        \"value\": \"FUTURE-1C-CATALOG\",\n        \"sort\": 100,\n        \"xmlId\": \"bx_5fc9f8c57ff3e\"\n      },\n      {\n        \"id\": 19,\n        \"basketId\": 9,\n        \"code\": \"PRODUCT.XML_ID\",\n        \"name\": \"Product XML_ID\",\n        \"value\": \"1000000475\",\n        \"sort\": 100,\n        \"xmlId\": \"bx_5fc9f8c57ffb2\"\n      }\n    ],\n    \"reservations\": [],\n    \"dateInsert\": \"2020-12-04T07:52:21.000Z\",\n    \"dateUpdate\": \"2022-11-02T05:10:13.000Z\"\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n422 — позиция не найдена:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"BITRIX_ERROR\",\n    \"message\": \"basket item is not exists\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Смотрите также\n\n- [Обновить позицию](.\u002Fupdate.md)\n- [Удалить позицию](.\u002Fdelete.md)\n- [Список позиций](.\u002Flist.md)\n- [Поля позиции](.\u002Ffields.md)\n- [Заказ](..\u002Forders\u002Fget.md)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n","\n## Обновить позицию корзины\n\n`PATCH \u002Fv1\u002Fbasket-items\u002F:id`\n\nОбновляет поля существующей позиции корзины. Передавайте только изменяемые поля плоско в корне JSON — без обёртки `fields`.\n\n## Параметры\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `id` (path) | number | да | Идентификатор позиции |\n\n## Поля для обновления (тело)\n\n| Параметр | Тип | Описание |\n|----------|-----|---------|\n| `quantity` | number | Количество |\n| `price` | number | Цена за единицу |\n| `basePrice` | number | Базовая цена до скидки |\n| `discountPrice` | number | Размер скидки за единицу |\n| `currency` | string | Валюта |\n| `name` | string | Переопределение названия товара |\n| `vatRate` | number | Ставка НДС в долях единицы |\n| `vatIncluded` | boolean | Включён ли НДС в цену |\n| `customPrice` | boolean | Защита цены от автопересчёта |\n| `weight` | number | Вес в граммах |\n| `measureCode` | number | Код единицы измерения |\n| `xmlId` | string | Внешний идентификатор |\n\nРедактируются все поля позиции, кроме служебных (`id`, `orderId`, `productId`, `productXmlId`, `catalogXmlId`, `dateInsert`, `dateUpdate`). Полный набор доступных полей виден в ответе [`GET \u002Fv1\u002Fbasket-items\u002F:id`](.\u002Fget.md).\n\n> **Частичное обновление.** Передавать `quantity` в каждом запросе не нужно. При отсутствии `quantity` в теле обёртка дочитывает текущее количество позиции и подставляет его — можно изменить только цену или другое поле. Если при таком частичном обновлении позиция не найдена, вернётся `404 ENTITY_NOT_FOUND`.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"quantity\": 3,\n    \"discountPrice\": 50\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"quantity\": 3,\n    \"discountPrice\": 50\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  method: 'PATCH',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    quantity: 3,\n    discountPrice: 50,\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  method: 'PATCH',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    quantity: 3,\n    discountPrice: 50,\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `data` | object | Обновлённый объект позиции со всеми полями |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": 9,\n    \"orderId\": 33,\n    \"productId\": 119,\n    \"name\": \"Домашние Тапочки Любимый Спорт\",\n    \"price\": 470,\n    \"basePrice\": 470,\n    \"discountPrice\": 50,\n    \"currency\": \"RUB\",\n    \"quantity\": 3,\n    \"vatRate\": 0,\n    \"vatIncluded\": true,\n    \"customPrice\": false,\n    \"canBuy\": true,\n    \"weight\": 0,\n    \"measureCode\": 796,\n    \"measureName\": \"шт\",\n    \"dateUpdate\": \"2026-05-13T11:58:14.000Z\"\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n422 — позиция не найдена:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"BITRIX_ERROR\",\n    \"message\": \"basket item is not exists\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 404 | `ENTITY_NOT_FOUND` | Позиция не найдена (частичный PATCH без `quantity` — определяется на предзагрузке) |\n| 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена (PATCH с явным `quantity`) |\n| 400 | `BITRIX_ERROR` | Некорректное значение поля |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Поля `id`, `orderId`, `productId`, `productXmlId`, `catalogXmlId`, `dateInsert` доступны только для чтения.** Они проставляются при создании, попытка изменить их игнорируется. Чтобы перенести позицию в другой заказ, удалите её через [`DELETE \u002Fv1\u002Fbasket-items\u002F:id`](.\u002Fdelete.md) и создайте новую через [`POST \u002Fv1\u002Fbasket-items`](.\u002Fcreate.md).\n\n**Защита цены через `customPrice`.** При `customPrice: true` цена позиции не будет пересчитана автоматически при изменении цены товара в каталоге.\n\n## Смотрите также\n\n- [Получить позицию](.\u002Fget.md)\n- [Список позиций](.\u002Flist.md)\n- [Удалить позицию](.\u002Fdelete.md)\n- [Batch](\u002Fdocs\u002Fbatch)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n","\n## Удалить позицию корзины\n\n`DELETE \u002Fv1\u002Fbasket-items\u002F:id`\n\nУдаляет позицию корзины по идентификатору. Восстановить удалённую позицию через API нельзя — создавайте новую при необходимости.\n\n## Параметры\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `id` (path) | number | да | Идентификатор позиции |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  method: 'DELETE',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nif (res.status === 204) {\n  console.log('Позиция удалена')\n}\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002F9', {\n  method: 'DELETE',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nif (res.status === 204) {\n  console.log('Позиция удалена')\n}\n```\n\n## Ответ\n\nПри успешном удалении возвращается HTTP-статус `204 No Content` с пустым телом — успех проверяется по статусу.\n\n## Пример ответа\n\n```http\nHTTP\u002F1.1 204 No Content\n```\n\n## Пример ответа при ошибке\n\n422 — позиция не найдена:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"BITRIX_ERROR\",\n    \"message\": \"basket item is not exists\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 422 | `BITRIX_ERROR` | Позиция с таким ID не найдена или уже удалена |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Заказ остаётся без изменений.** Удаление позиции не затрагивает родительский заказ — только пропадает одна строка корзины. Сумма заказа (`orders.price`) при этом не пересчитывается автоматически.\n\n## Смотрите также\n\n- [Список позиций](.\u002Flist.md)\n- [Получить позицию](.\u002Fget.md)\n- [Обновить позицию](.\u002Fupdate.md)\n- [Обновить заказ](..\u002Forders\u002Fupdate.md)\n- [Batch](\u002Fdocs\u002Fbatch)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n","\n## Поиск позиций корзины\n\n`POST \u002Fv1\u002Fbasket-items\u002Fsearch`\n\nПоиск позиций корзины с фильтрацией и автоматической пагинацией. Аналогичен [`GET \u002Fv1\u002Fbasket-items`](.\u002Flist.md), но параметры передаются в теле POST-запроса — подходит для сложных запросов с большим количеством условий.\n\n## Поля запроса (тело)\n\n| Параметр | Тип | По умолч. | Описание |\n|----------|-----|-----------|---------|\n| `filter` | object | — | Фильтрация по полям позиции.\u003Cbr>[Синтаксис фильтрации](\u002Fdocs\u002Ffiltering) |\n| `limit` | number | `50` | Количество записей (до 5000) |\n| `select` | string[] | — | Выборка полей: `[\"id\", \"orderId\", \"name\", \"quantity\", \"price\"]` |\n| `order` | object | — | Сортировка: `{ \"id\": \"desc\" }` |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Fsearch\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"filter\": { \"orderId\": 33 },\n    \"limit\": 10,\n    \"select\": [\"id\", \"orderId\", \"name\", \"quantity\", \"price\", \"currency\"]\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Fsearch\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"filter\": { \"orderId\": 33 },\n    \"limit\": 10,\n    \"select\": [\"id\", \"orderId\", \"name\", \"quantity\", \"price\", \"currency\"]\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Fsearch', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    filter: { orderId: 33 },\n    limit: 10,\n    select: ['id', 'orderId', 'name', 'quantity', 'price', 'currency'],\n  }),\n})\n\nconst { success, data, meta } = await res.json()\nconsole.log('Найдено:', meta.total)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Fsearch', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    filter: { orderId: 33 },\n    limit: 10,\n    select: ['id', 'orderId', 'name', 'quantity', 'price', 'currency'],\n  }),\n})\n\nconst { success, data, meta } = await res.json()\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data` | array | Массив позиций корзины |\n| `meta.total` | number | Общее количество записей, соответствующих фильтру |\n| `meta.hasMore` | boolean | Есть ли ещё записи за пределами `limit` |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": 9,\n      \"orderId\": 33,\n      \"name\": \"Домашние Тапочки Любимый Спорт\",\n      \"quantity\": 1,\n      \"price\": 470,\n      \"currency\": \"RUB\"\n    }\n  ],\n  \"meta\": {\n    \"total\": 1,\n    \"hasMore\": false\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n400 — фильтр по несуществующему полю:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"UNKNOWN_FILTER_FIELD\",\n    \"message\": \"Unknown filter field 'foo' for entity 'basket-items'. Available: …\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 400 | `UNKNOWN_FILTER_FIELD` | Фильтр по полю, которого нет в схеме |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**`select` ограничивает поля в ответе.** Если передан `select`, в каждом элементе `data[]` будут только перечисленные поля. Без `select` возвращаются все поля позиции.\n\n**Поиск товара по всем заказам.** Фильтр `{\"productId\": 119}` без `orderId` найдёт все позиции с этим товаром по всему порталу — это даёт срез продаж конкретного товара.\n\n## Смотрите также\n\n- [Список позиций](.\u002Flist.md)\n- [Получить позицию](.\u002Fget.md)\n- [Заказ](..\u002Forders\u002Fget.md)\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering)\n- [Batch](\u002Fdocs\u002Fbatch)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n","\n## Поля позиции корзины\n\n`GET \u002Fv1\u002Fbasket-items\u002Ffields`\n\nВозвращает схему полей позиции корзины: типы, флаги только-для-чтения, список агрегируемых полей.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Ffields\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Ffields\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Ffields', {\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n  },\n})\n\nconst { data } = await res.json()\nconsole.log('Поля позиции:', Object.keys(data.fields))\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Ffields', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\n\nconst { data } = await res.json()\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `id` | number | Идентификатор позиции (только чтение) |\n| `orderId` | number \\| null | Идентификатор заказа. Источник: [`GET \u002Fv1\u002Forders`](..\u002Forders\u002Flist.md). У свободных позиций без заказа — `null` |\n| `productId` | number | Идентификатор товара в каталоге. Источник: [`GET \u002Fv1\u002Fcatalog-products`](\u002Fdocs\u002Fentities\u002Fcatalog-products). `0` — виртуальная позиция без привязки к каталогу |\n| `name` | string | Название позиции |\n| `price` | number | Цена за единицу с учётом скидки |\n| `basePrice` | number | Базовая цена до скидки |\n| `discountPrice` | number | Размер скидки за единицу |\n| `customPrice` | boolean | Цена задана вручную и не пересчитывается при изменении товара в каталоге |\n| `currency` | string | Валюта позиции. Список: [`GET \u002Fv1\u002Fcurrencies`](\u002Fdocs\u002Fentities\u002Fcurrencies) |\n| `quantity` | number | Количество |\n| `sort` | number | Порядок позиции в корзине. По умолчанию `100` |\n| `weight` | number \\| null | Вес единицы в граммах. У позиций без веса — `null` |\n| `dimensions` | string \\| null | Габариты в формате сериализации PHP. У позиций без габаритов — `null` |\n| `measureCode` | number \\| null | Код единицы измерения. `796` — шт, `163` — г, `006` — м. Может быть `null` |\n| `measureName` | string \\| null | Название единицы измерения. Может быть `null` |\n| `canBuy` | boolean | Доступна ли позиция к покупке |\n| `vatRate` | number \\| null | Ставка НДС в долях единицы. `0.20` = 20%. У позиций без НДС — `null` |\n| `vatIncluded` | boolean | Включён ли НДС в цену |\n| `xmlId` | string | Внешний идентификатор позиции |\n| `productXmlId` | string \\| null | Внешний идентификатор товара. Может быть `null` |\n| `catalogXmlId` | string \\| null | Внешний идентификатор каталога. Может быть `null` |\n| `dateInsert` | datetime | Дата создания (только чтение) |\n| `dateUpdate` | datetime | Дата последнего изменения (только чтение) |\n| `barcodeMulti` | boolean | Позиция учитывается по нескольким штрихкодам |\n| `type` | string \\| null | Тип позиции (только чтение). На живых порталах всегда `null` |\n| `properties` | array | Свойства позиции, только чтение. Каждый элемент: `{basketId, code, id, name, sort, value, xmlId}`. Возвращается только `GET \u002Fv1\u002Fbasket-items\u002F:id`, в списке — нет |\n| `reservations` | array | Резервы позиции на складах, только чтение. Возвращается только `GET \u002Fv1\u002Fbasket-items\u002F:id`, в списке — нет |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"fields\": {\n      \"id\": { \"type\": \"number\", \"readonly\": true },\n      \"orderId\": { \"type\": \"number\", \"readonly\": false },\n      \"productId\": { \"type\": \"number\", \"readonly\": false },\n      \"name\": { \"type\": \"string\", \"readonly\": false },\n      \"price\": { \"type\": \"number\", \"readonly\": false },\n      \"basePrice\": { \"type\": \"number\", \"readonly\": false },\n      \"discountPrice\": { \"type\": \"number\", \"readonly\": false },\n      \"customPrice\": { \"type\": \"boolean\", \"readonly\": false },\n      \"currency\": { \"type\": \"string\", \"readonly\": false },\n      \"quantity\": { \"type\": \"number\", \"readonly\": false },\n      \"sort\": { \"type\": \"number\", \"readonly\": false },\n      \"weight\": { \"type\": \"number\", \"readonly\": false, \"nullable\": true },\n      \"dimensions\": { \"type\": \"string\", \"readonly\": false, \"nullable\": true },\n      \"measureCode\": { \"type\": \"number\", \"readonly\": false, \"nullable\": true },\n      \"measureName\": { \"type\": \"string\", \"readonly\": false, \"nullable\": true },\n      \"canBuy\": { \"type\": \"boolean\", \"readonly\": false },\n      \"vatRate\": { \"type\": \"number\", \"readonly\": false, \"nullable\": true },\n      \"vatIncluded\": { \"type\": \"boolean\", \"readonly\": false },\n      \"xmlId\": { \"type\": \"string\", \"readonly\": false },\n      \"productXmlId\": { \"type\": \"string\", \"readonly\": false, \"nullable\": true },\n      \"catalogXmlId\": { \"type\": \"string\", \"readonly\": false, \"nullable\": true },\n      \"dateInsert\": { \"type\": \"datetime\", \"readonly\": true },\n      \"dateUpdate\": { \"type\": \"datetime\", \"readonly\": true },\n      \"barcodeMulti\": { \"type\": \"boolean\", \"readonly\": false },\n      \"type\": { \"type\": \"string\", \"readonly\": true },\n      \"properties\": { \"type\": \"array\", \"readonly\": true },\n      \"reservations\": { \"type\": \"array\", \"readonly\": true }\n    },\n    \"aggregatable\": [\"price\", \"quantity\", \"currency\", \"orderId\", \"productId\"],\n    \"batch\": [\"create\", \"update\", \"delete\"]\n  }\n}\n```\n\n## Пример ответа при ошибке\n\n403 — нет скоупа:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"SCOPE_DENIED\",\n    \"message\": \"This endpoint requires 'sale' scope\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Смотрите также\n\n- [Список позиций](.\u002Flist.md)\n- [Добавить позицию](.\u002Fcreate.md)\n- [Агрегация позиций](.\u002Faggregate.md)\n- [Entity API](\u002Fdocs\u002Fentity-api)\n","\n## Агрегация позиций корзины\n\n`POST \u002Fv1\u002Fbasket-items\u002Faggregate`\n\nПодсчёт количества позиций и числовые агрегации (`sum`, `avg`, `min`, `max`) по полям `price` и `quantity`. Поддерживает фильтрацию и группировку по `orderId`, `productId`, `currency`.\n\n## Стандартные поля\n\n| Поле | Назначение |\n|------|------------|\n| `price` | Числовое — подходит для `sum` \u002F `avg` \u002F `min` \u002F `max` (агрегации по цене за единицу) |\n| `quantity` | Числовое — подходит для `sum` \u002F `avg` \u002F `min` \u002F `max` (агрегации по количеству) |\n| `currency` | Категориальное — используется в `groupBy` (по валюте) |\n| `orderId`, `productId` | Идентификаторы — используются в `groupBy` (по заказу или товару) |\n\nПолный список агрегируемых полей перечислен в таблице выше.\n\n## Поля запроса (тело)\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `aggregate` | array | нет | Массив агрегаций: `[{ \"field\": \"quantity\", \"function\": \"sum\" }]`. Функции: `count`, `sum`, `avg`, `min`, `max`. Для `count` поле — `\"*\"`. Без параметра — только `count` |\n| `filter` | object | нет | Фильтрация — те же поля, что в [`GET \u002Fv1\u002Fbasket-items`](.\u002Flist.md). [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering) |\n| `groupBy` | string \\| string[] | нет | Поле или массив полей для группировки (максимум 5) |\n| `groupOrderBy` | array | нет | Сортировка групп: `[{ \"field\": \"quantity:sum\", \"direction\": \"desc\" }]` |\n| `groupLimit` | number | нет | Ограничение количества возвращаемых групп (1-1000) |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Faggregate\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"aggregate\": [\n      { \"field\": \"quantity\", \"function\": \"sum\" },\n      { \"field\": \"price\", \"function\": \"avg\" }\n    ],\n    \"groupBy\": \"productId\",\n    \"groupLimit\": 5\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Faggregate\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"aggregate\": [\n      { \"field\": \"quantity\", \"function\": \"sum\" },\n      { \"field\": \"price\", \"function\": \"avg\" }\n    ],\n    \"groupBy\": \"productId\",\n    \"groupLimit\": 5\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Faggregate', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    aggregate: [\n      { field: 'quantity', function: 'sum' },\n      { field: 'price', function: 'avg' },\n    ],\n    groupBy: 'productId',\n    groupLimit: 5,\n  }),\n})\n\nconst { success, data } = await res.json()\nconsole.log('Топ-5 товаров по продажам:', data.groups)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbasket-items\u002Faggregate', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    aggregate: [{ field: 'quantity', function: 'sum' }],\n    groupBy: 'productId',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n## Другие сценарии\n\nПодсчёт записей — `count` с полем `\"*\"`, самый быстрый запрос без выгрузки записей. Без массива `aggregate` результат тот же:\n\n```json\n{ \"aggregate\": [{ \"field\": \"*\", \"function\": \"count\" }] }\n```\n\nОбщая стоимость всех позиций в заказе:\n\n```json\n{\n  \"aggregate\": [{ \"field\": \"price\", \"function\": \"sum\" }],\n  \"filter\": { \"orderId\": 33 }\n}\n```\n\nТоп-3 товаров по сумме продаж:\n\n```json\n{\n  \"aggregate\": [{ \"field\": \"quantity\", \"function\": \"sum\" }],\n  \"groupBy\": \"productId\",\n  \"groupOrderBy\": [{ \"field\": \"quantity:sum\", \"direction\": \"desc\" }],\n  \"groupLimit\": 3\n}\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.count` | number | Общее количество позиций, соответствующих фильтру |\n| `data.aggregates` | object | Результаты агрегаций: `{ \"quantity\": { \"sum\": ... }, \"price\": { \"avg\": ... } }` |\n| `data.groups` | array | Группы (только при `groupBy`) |\n| `data.meta.totalRecords` | number | Общее количество записей |\n| `data.meta.recordsProcessed` | number | Количество обработанных записей (до 5000) |\n| `data.meta.truncated` | boolean | `true`, если записей больше 5000 |\n| `data.meta.groupTotal` | number | Количество групп до `groupLimit` |\n| `data.meta.groupsTruncated` | boolean | Был ли список групп обрезан `groupLimit` |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 261,\n    \"aggregates\": {\n      \"quantity\": { \"sum\": 412 }\n    },\n    \"groups\": [\n      {\n        \"productId\": 119,\n        \"count\": 23,\n        \"aggregates\": { \"quantity\": { \"sum\": 47 } }\n      },\n      {\n        \"productId\": 245,\n        \"count\": 18,\n        \"aggregates\": { \"quantity\": { \"sum\": 36 } }\n      },\n      {\n        \"productId\": 87,\n        \"count\": 14,\n        \"aggregates\": { \"quantity\": { \"sum\": 21 } }\n      }\n    ],\n    \"meta\": {\n      \"totalRecords\": 261,\n      \"recordsProcessed\": 261,\n      \"truncated\": false,\n      \"groupTotal\": 89,\n      \"groupsTruncated\": true\n    }\n  }\n}\n```\n\nБез `groupBy` поле `data.groups` в ответе отсутствует.\n\n## Пример ответа при ошибке\n\n400 — поле в `groupBy` не поддерживает агрегацию:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_PARAMS\",\n    \"message\": \"groupBy field 'foo' is not aggregatable on this entity. Available: price, quantity, currency, orderId, productId.\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 400 | `INVALID_PARAMS` | Неизвестная функция агрегации |\n| 400 | `INVALID_PARAMS` | Несуществующее числовое поле в `aggregate[].field` — сообщение `Field 'foo' not found. Available numeric fields: …` |\n| 400 | `INVALID_PARAMS` | Поле в `groupBy` не поддерживает агрегацию — сообщение содержит список допустимых полей |\n| 400 | `INVALID_PARAMS` | Передано больше 5 полей в `groupBy` |\n| 400 | `INVALID_PARAMS` | Зарезервированные ключевые слова в `groupBy`: `count`, `aggregates`, `meta`, `groups` |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `sale` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**`count` против числовых функций.** `count` считается одним запросом в Битрикс24 — записи не выгружаются, ответ возвращается быстро на любом объёме. `sum` \u002F `avg` \u002F `min` \u002F `max` подгружают записи постранично (максимум 5000) и считают на стороне Вайбкод. При более чем 5000 записях `meta.truncated` будет `true`.\n\n**Учёт незавершённых корзин.** В выборку попадают и позиции с `orderId: null` (товары в незавершённых корзинах). Чтобы исключить их, добавьте `filter[orderId][!]=null`.\n\n## Смотрите также\n\n- [Список позиций](.\u002Flist.md)\n- [Поиск позиций](.\u002Fsearch.md)\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization)\n"]