[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-entities\u002Frequisites\u002Faggregate":3,"docs-tabs-entities\u002Frequisites\u002Faggregate":6},{"content":4,"lastmod":5},"\n## Агрегация реквизитов\n\n`POST \u002Fv1\u002Frequisites\u002Faggregate`\n\nПодсчёт количества реквизитов с фильтрацией и группировкой.\n\n**Стандартные поля для `groupBy`:**\n\n- `rqInn`, `rqKpp`, `rqOgrn`, `rqOgrnip`, `rqOkpo` — налоговые\u002Fрегистрационные идентификаторы (ИНН, КПП, ОГРН, ОГРНИП, ОКПО)\n- `rqVatId` — VAT\u002Fналоговый номер (для не-РФ стран)\n- `rqResidenceCountry` — страна резидентства\n- `rqCompanyName` — название компании\n- `entityTypeId` — тип владельца (1 — лид, 3 — контакт, 4 — компания)\n- `presetId` — шаблон реквизита\n- `active` — признак активности\n\nВсе поля в `aggregatable` — идентификаторы и категориальные коды, поэтому по ним работает `groupBy`. Группировка по `rqInn` (или другому идентификатору) — самый быстрый способ найти дубли реквизитов одним вызовом, без выгрузки всех записей. Числовые функции (`sum`\u002F`avg`\u002F`min`\u002F`max`) по этим полям недоступны (это строки) — используйте для них пользовательские UF-поля числового типа.\n\n**Контракт `count`.** Функция `count` принимает ТОЛЬКО `field: \"*\"` — `{ \"field\": \"*\", \"function\": \"count\" }`. Передача `field: \"id\"` (или любого другого имени) вернёт `400 INVALID_PARAMS` с сообщением `count aggregate requires field \"*\"`. Это намеренный контракт: `count` считает строки, а не значения конкретного поля.\n\n**Пользовательские поля (UF):** UF-поля типов `integer`, `double`, `money` — для числовых функций; UF любого типа — для `groupBy`. На практике у реквизита обычно UF-поля строкового типа (ИНН, номер телефона, адрес) — их можно использовать только в `groupBy`. Полный список UF-полей конкретного портала приходит в тексте ошибки `INVALID_PARAMS`, если передать несуществующее имя.\n\n## Поля запроса (body)\n\n| Параметр | Тип | Обяз. | Описание |\n|----------|-----|:-----:|---------|\n| `aggregate` | array | нет | Массив агрегаций. Каждый элемент: `{ \"field\": \"*\", \"function\": \"count\" }`. Без параметра — только count |\n| `filter` | object | нет | Фильтрация по полям `GET \u002Fv1\u002Frequisites\u002Ffields`.\u003Cbr>[Синтаксис фильтрации](\u002Fdocs\u002Ffiltering) |\n| `groupBy` | string \\| string[] | нет | Поле или массив полей для группировки (максимум 5). Принимает UF-поля любого типа |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Frequisites\u002Faggregate\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"filter\": { \"active\": true },\n    \"groupBy\": \"entityTypeId\"\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Frequisites\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    \"filter\": { \"active\": true },\n    \"groupBy\": \"entityTypeId\"\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Frequisites\u002Faggregate', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson',\n  },\n  body: JSON.stringify({\n    filter: { active: true },\n    groupBy: 'entityTypeId',\n  }),\n})\n\nconst { success, data } = await res.json()\nconsole.log('Всего активных реквизитов:', data.count)\nconsole.log('По типам владельцев:', data.groups)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Frequisites\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    filter: { active: true },\n    groupBy: 'entityTypeId',\n  }),\n})\n\nconst { success, data } = await res.json()\n```\n\n> Для группировки по нескольким полям передайте массив: `\"groupBy\": [\"entityTypeId\", \"presetId\"]` (максимум 5).\n\n## Другие сценарии\n\nОбщее количество реквизитов в портале — самый быстрый запрос, без выгрузки записей:\n\n```json\n{}\n```\n\nПоиск дублей по ИНН одним вызовом — группы с `count > 1` содержат повторяющиеся ИНН:\n\n```json\n{ \"aggregate\": [{ \"field\": \"*\", \"function\": \"count\" }], \"groupBy\": \"rqInn\" }\n```\n\nГруппировка по UF-полю (любой тип — например, пользовательский классификатор):\n\n```json\n{ \"groupBy\": \"UF_CRM_CLASSIFIER\" }\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.count` | number | Количество записей, соответствующих фильтру |\n| `data.aggregates` | object | Результаты агрегаций (для реквизитов обычно пустой) |\n| `data.groups` | array | Группы (только при `groupBy`). Каждый элемент: поля группировки + `count` |\n| `data.meta.totalRecords` | number | Общее количество записей |\n| `data.meta.recordsProcessed` | number | Количество обработанных записей |\n| `data.meta.truncated` | boolean | Был ли результат ограничен. `true` при более 5000 записей |\n\n## Пример ответа\n\nОтвет на основной запрос (`groupBy: \"entityTypeId\"`):\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"count\": 164,\n    \"aggregates\": {},\n    \"groups\": [\n      { \"entityTypeId\": 4, \"count\": 120 },\n      { \"entityTypeId\": 3, \"count\": 40 },\n      { \"entityTypeId\": 1, \"count\": 4 }\n    ],\n    \"meta\": {\n      \"totalRecords\": 164,\n      \"recordsProcessed\": 164,\n      \"truncated\": false\n    }\n  }\n}\n```\n\nБез `groupBy` поле `data.groups` в ответе отсутствует.\n\n## Пример ответа при ошибке\n\n403 — нет скоупа:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"SCOPE_DENIED\",\n    \"message\": \"Requires 'crm' scope\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|---------|\n| 400 | `INVALID_PARAMS` | Невалидное имя функции агрегации или несуществующее поле |\n| 403 | `SCOPE_DENIED` | API-ключ не имеет скоупа `crm` |\n| 401 | `TOKEN_MISSING` | API-ключ не имеет настроенных токенов |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**Money-поля.** UF-поля типа `money` хранятся в формате `\"сумма|валюта\"` (`\"1500|RUB\"`) — агрегат извлекает числовую часть автоматически, складывать можно без парсинга.\n\n**Без массива `aggregate` — только count.** Если не передать `aggregate`, метод вернёт `count` записей с учётом фильтра.\n\n**Фильтрация по UF работает.** В `filter` можно передавать любые поля — стандартные и пользовательские, любого типа. Например, `{ \"filter\": { \"UF_CRM_1234\": \"value\" } }` вернёт количество реквизитов с этим значением UF.\n\n**Ограничение 5000 записей.** Если под фильтр попадает больше 5000 записей, результат будет помечен `meta.truncated: true`. Для точного подсчёта больших выборок используйте `meta.total` в ответе `GET \u002Fv1\u002Frequisites` с `limit=1` — там хранится реальное количество.\n\n## Смотрите также\n\n- [Список реквизитов](\u002Fdocs\u002Fentities\u002Frequisites\u002Flist) — `meta.total` даёт точное число записей\n- [Поиск реквизитов](\u002Fdocs\u002Fentities\u002Frequisites\u002Fsearch) — POST-запрос с фильтрами\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering)\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization) — rate limits\n","2026-06-24",{}]