Агрегация элементов

POST /v1/items/:entityTypeId/aggregate

Подсчёт количества, сумма, среднее, минимум и максимум по элементам смарт-процесса с фильтрацией и группировкой. Смарт-процесс задаётся в пути через entityTypeId — ID типа процесса, который можно получить через GET /v1/smart-processes.

Стандартные поля:

  • opportunity — сумма элемента (числовое агрегирование имеет смысл)
  • categoryId — категория (для groupBy)
  • assignedById — ответственный (для groupBy)
  • stageId — стадия (для groupBy)
  • createdBy — создал (для groupBy)
  • updatedBy — последний изменил (для groupBy)

Пользовательские поля (UF): имена UF-полей имеют префикс с внутренним номером типа смарт-процесса — ufCrm<typeId>_* (например, ufCrm7_1652689362). Этот номер не равен entityTypeId из пути — точные имена UF-полей берите из ответа `GET /v1/items/:entityTypeId/fields` или из текста ошибки INVALID_PARAMS, она перечисляет доступные поля портала. Типы integer, double, money — для числовых функций, UF любого типа — для groupBy. Основной источник бизнес-данных в смарт-процессах — именно UF.

Path-параметры

Параметр Тип Обяз. Описание
entityTypeId number да ID типа смарт-процесса. Для пользовательских смарт-процессов — любое положительное целое из GET /v1/smart-processes. Значения 1 (лиды), 2 (сделки), 3 (контакты), 4 (компании), 7 (предложения), 31 (счета) зарезервированы — используйте специализированные API: /v1/deals, /v1/leads и т.д.

Поля запроса (body)

Параметр Тип Обяз. Описание
aggregate array нет Массив агрегаций. Каждый элемент: { "field": "opportunity", "function": "sum" }. Функции: count, sum, avg, min, max. Для count поле — "*". Без массива — только count
filter object нет Фильтрация по полям GET /v1/items/:entityTypeId/fields. Синтаксис фильтрации
groupBy string | string[] нет Поле или массив полей для группировки (максимум 5). Принимает стандартные поля и UF-поля любого типа

Примеры

curl — личный ключ

Terminal
curl -X POST "https://vibecode.bitrix24.tech/v1/items/177/aggregate" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "field": "opportunity", "function": "sum" },
      { "field": "opportunity", "function": "avg" }
    ],
    "filter": { "categoryId": 7 },
    "groupBy": "stageId"
  }'

curl — OAuth-приложение

Terminal
curl -X POST "https://vibecode.bitrix24.tech/v1/items/177/aggregate" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "field": "opportunity", "function": "sum" },
      { "field": "opportunity", "function": "avg" }
    ],
    "filter": { "categoryId": 7 },
    "groupBy": "stageId"
  }'

JavaScript — личный ключ

javascript
const entityTypeId = 177

const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/${entityTypeId}/aggregate`, {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    aggregate: [
      { field: 'opportunity', function: 'sum' },
      { field: 'opportunity', function: 'avg' },
    ],
    filter: { categoryId: 7 },
    groupBy: 'stageId',
  }),
})

const { success, data } = await res.json()
console.log('Всего элементов:', data.count)
console.log('По стадиям:', data.groups)

JavaScript — OAuth-приложение

javascript
const entityTypeId = 177

const res = await fetch(`https://vibecode.bitrix24.tech/v1/items/${entityTypeId}/aggregate`, {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    aggregate: [
      { field: 'opportunity', function: 'sum' },
      { field: 'opportunity', function: 'avg' },
    ],
    filter: { categoryId: 7 },
    groupBy: 'stageId',
  }),
})

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

Для группировки по нескольким полям передайте массив: "groupBy": ["stageId", "categoryId"] (максимум 5).

Другие сценарии

Подсчёт записей — count с полем "*", самый быстрый запрос без выгрузки записей. Без массива aggregate результат тот же:

JSON
{ "aggregate": [{ "field": "*", "function": "count" }] }

Работа с пользовательскими полями (UF) — sum по UF + группировка по другому UF:

JSON
{
  "aggregate": [{ "field": "ufCrm7_1741091916816", "function": "sum" }],
  "groupBy": "ufCrm7_1652689362"
}

Поля ответа

Поле Тип Описание
success boolean Всегда true при успехе
data.count number Количество элементов, соответствующих фильтру
data.aggregates object Результаты агрегаций: { "opportunity": { "sum": 65911, "avg": 4707.92 } }
data.groups array Группы (только при groupBy). Каждый элемент: поля группировки + count + aggregates
data.meta.totalRecords number Общее количество записей под фильтр
data.meta.recordsProcessed number Сколько записей было фактически обработано для агрегации
data.meta.truncated boolean true, если под фильтр попало больше 5000 записей
data.meta.groupTotal number Количество групп (только при groupBy)
data.meta.groupsTruncated boolean true, если список групп был усечён

Пример ответа

Ответ на основной запрос (агрегации + groupBy: "stageId"):

JSON
{
  "success": true,
  "data": {
    "count": 14,
    "aggregates": {
      "opportunity": { "sum": 65911, "avg": 4707.92 }
    },
    "groups": [
      {
        "stageId": "DT177_7:NEW",
        "count": 8,
        "aggregates": { "opportunity": { "sum": 40000 } }
      },
      {
        "stageId": "DT177_7:SUCCESS",
        "count": 6,
        "aggregates": { "opportunity": { "sum": 25911 } }
      }
    ],
    "meta": {
      "totalRecords": 14,
      "recordsProcessed": 14,
      "truncated": false,
      "groupTotal": 2,
      "groupsTruncated": false
    }
  }
}

Без groupBy поле data.groups в ответе отсутствует.

Пример ответа при ошибке

400 — зарезервированный entityTypeId (для стандартных CRM-сущностей):

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_DYNAMIC_PARAM",
    "message": "entityTypeId 2 has a dedicated API: use /v1/deals instead"
  }
}

Ошибки

HTTP Код Описание
400 INVALID_DYNAMIC_PARAM entityTypeId не является положительным целым или является зарезервированным (1, 2, 3, 4, 7, 31)
400 INVALID_PARAMS Некорректное имя функции, несуществующее поле или нечисловое поле в sum/avg/min/max
401 TOKEN_MISSING API-ключ не имеет настроенных токенов
403 SCOPE_DENIED API-ключ не имеет скоупа crm

Полный список общих ошибок API — Ошибки.

Известные особенности

Без массива aggregate — только count. Если не передать aggregate, метод сделает один быстрый вызов в Битрикс24 и вернёт count записей под фильтр. Подходит для счётчиков на дашбордах.

Несколько агрегаций в одном запросе. Можно объединить в одном вызове: [{ "field": "opportunity", "function": "sum" }, { "field": "opportunity", "function": "avg" }].

Money-поля. UF-поля типа money хранятся в формате "сумма|валюта" ("1500|RUB") — агрегат извлекает числовую часть автоматически, складывать можно без парсинга.

Фильтрация по UF работает. В filter можно передавать любые поля — стандартные и пользовательские, любого типа. Например, { "filter": { "ufCrm7_1652689362": 1435 } } вернёт количество элементов с этим значением UF.

Ограничение 5000 записей. Числовые агрегации подгружают записи постранично и считают на стороне Вайбкод. Если под фильтр попадает больше 5000 записей, результат будет помечен meta.truncated: true — берётся только первые 5000. Для точного количества используйте count (он работает на любом объёме) или сужайте фильтр.

Зарезервированные entityTypeId. Значения 1 (лиды), 2 (сделки), 3 (контакты), 4 (компании), 7 (предложения), 31 (счета) обслуживаются специализированными API — используйте /v1/deals/aggregate, /v1/leads/aggregate, /v1/contacts/aggregate, /v1/companies/aggregate, /v1/quotes/aggregate, /v1/invoices/aggregate.

Смотрите также