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

Aggregate orders

POST /v1/orders/aggregate

Counts orders and performs numeric aggregations (sum, avg, min, max) on the price field. Supports filtering and grouping by statusId, payed, canceled, personTypeId, responsibleId, userId.

Standard fields

Field Purpose
Fieldprice PurposeOrder total: the main field for sum / avg / min / max. Numeric functions accept any field with the number type
FieldstatusId PurposeCategorical field used in groupBy (order statuses)
Fieldpayed, canceled PurposeBoolean fields used in groupBy (paid / canceled)
FieldpersonTypeId, responsibleId, userId PurposeIDs used in groupBy (by payer type, responsible person, buyer)

Fields for groupBy are listed in the aggregatable array in GET /v1/orders/fields. Numeric functions accept fields with the number type from the same response.

Request fields (body)

Field Type Required Description
Fieldaggregate Typearray Requiredno DescriptionArray of aggregations. Without this parameter, only count is returned
Fieldaggregate[].field Typestring Requiredyes DescriptionField in each array item. For count, use "*"; for numeric functions, use a field with the number type from Order fields
Fieldaggregate[].function Typestring Requiredyes DescriptionFunction in each array item: count, sum, avg, min, max
Fieldfilter Typeobject Requiredno DescriptionFiltering uses the same fields as GET /v1/orders. Filtering syntax
FieldgroupBy Typestring | string[] Requiredno DescriptionField or array of fields for grouping (up to 5). Allowed values come from the aggregatable array
FieldgroupOrderBy Typearray Requiredno DescriptionGroup sorting. Used with groupBy
FieldgroupOrderBy[].field Typestring Requiredyes DescriptionField in each array item: count, a dimension name from groupBy, or a requested <field>:<function> pair, such as price:sum
FieldgroupOrderBy[].direction Typestring Requiredno DescriptionSort direction: asc or desc. Defaults to desc
FieldgroupLimit Typenumber Requiredno DescriptionLimit on the number of groups returned (1-1000)

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/orders/aggregate" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "field": "price", "function": "sum" },
      { "field": "price", "function": "avg" }
    ],
    "groupBy": "statusId"
  }'

curl — OAuth application

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/orders/aggregate" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "aggregate": [
      { "field": "price", "function": "sum" },
      { "field": "price", "function": "avg" }
    ],
    "groupBy": "statusId"
  }'

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/orders/aggregate', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    aggregate: [
      { field: 'price', function: 'sum' },
      { field: 'price', function: 'avg' },
    ],
    groupBy: 'statusId',
  }),
})

const { success, data } = await res.json()
// data.groups — array of groups by statusId
console.log(data.groups)

JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/orders/aggregate', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    aggregate: [
      { field: 'price', function: 'sum' },
      { field: 'price', function: 'avg' },
    ],
    groupBy: 'statusId',
  }),
})

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

Other scenarios

The blocks below are request bodies.

Count records with count and the "*" field: the fastest request, without fetching records. Omitting the aggregate array produces the same result:

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

Sum across all orders without grouping:

JSON
{
  "aggregate": [{ "field": "price", "function": "sum" }]
}

Top 3 statuses by order total, with sorting:

JSON
{
  "aggregate": [{ "field": "price", "function": "sum" }],
  "groupBy": "statusId",
  "groupOrderBy": [{ "field": "price:sum", "direction": "desc" }],
  "groupLimit": 3
}

Response fields

Field Type Description
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata.count Typenumber DescriptionTotal number of orders matching the filter
Fielddata.aggregates Typeobject DescriptionAggregation results: { "price": { "sum": ..., "avg": ... } }
Fielddata.groups Typearray DescriptionGroups (present only with groupBy). Each item: grouping fields + count + aggregates
Fielddata.meta.totalRecords Typenumber DescriptionTotal number of records matching the filter
Fielddata.meta.recordsProcessed Typenumber DescriptionNumber of records processed (up to 5000)
Fielddata.meta.truncated Typeboolean Descriptiontrue if the numbers were not calculated across all records matching the filter: fewer records were read than reported by data.count, including when more than 5000 records match, or retrieval stopped because of an error in a page of results. The shortfall is returned in data.meta.recordsShortfall; an interrupted retrieval is reported in data.meta.pageErrorSample. Always present and false for a complete response. If the request has neither groupBy nor numeric functions, records are not fetched and the flag is always false
Fielddata.meta.groupTotal Typenumber DescriptionNumber of groups before applying groupLimit (only with groupBy)
Fielddata.meta.groupsTruncated Typeboolean DescriptionWhether the list of groups was truncated by groupLimit

Response example

JSON
{
  "success": true,
  "data": {
    "count": 207,
    "aggregates": {
      "price": {
        "sum": 2916702.5999999996,
        "avg": 14090.35072463768
      }
    },
    "groups": [
      {
        "statusId": "S",
        "count": 1,
        "aggregates": {
          "price": {
            "sum": 0,
            "avg": 0
          }
        }
      },
      {
        "statusId": "N",
        "count": 191,
        "aggregates": {
          "price": {
            "sum": 2902635.1299999994,
            "avg": 15197.042565445023
          }
        }
      },
      {
        "statusId": "T",
        "count": 8,
        "aggregates": {
          "price": {
            "sum": 3098.5,
            "avg": 387.3125
          }
        }
      },
      {
        "statusId": "P",
        "count": 6,
        "aggregates": {
          "price": {
            "sum": 9958.97,
            "avg": 1659.8283333333331
          }
        }
      },
      {
        "statusId": "F",
        "count": 1,
        "aggregates": {
          "price": {
            "sum": 1010,
            "avg": 1010
          }
        }
      }
    ],
    "meta": {
      "totalRecords": 207,
      "recordsProcessed": 207,
      "truncated": false,
      "groupTotal": 5,
      "groupsTruncated": false
    }
  }
}

Without groupBy, the data.groups field is absent from the response.

Error response example

400 — the field in groupBy is not aggregatable:

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "groupBy field 'foo' is not aggregatable on this entity. Available: price, statusId, payed, canceled, personTypeId, responsibleId, userId."
  }
}

Errors

HTTP Code Description
HTTP400 CodeINVALID_PARAMS DescriptionUnknown function or nonexistent field in aggregate / groupBy; the message lists the allowed fields
HTTP400 CodeINVALID_PARAMS DescriptionMore than 5 fields were passed in groupBy
HTTP400 CodeINVALID_PARAMS DescriptionReserved keywords in groupBy: count, aggregates, meta, groups
HTTP403 CodeSCOPE_DENIED DescriptionThe API key does not have the sale scope
HTTP401 CodeTOKEN_MISSING DescriptionThe API key has no configured tokens
HTTP429 CodeRATE_LIMITED DescriptionRate limit exceeded: 300 requests per minute per portal. All API keys of the portal share one limit. The current limit is returned in the x-ratelimit-limit header. Retry after the delay in the Retry-After header

For the full list of common API errors, see Errors.

Known specifics

count versus numeric functions. If the request has neither groupBy nor numeric functions, count is calculated with a single Bitrix24 request without fetching records. Grouping fetches records. sum / avg / min / max fetch records page by page (up to 5000) and calculate results on the Vibecode side. With more than 5000 records, meta.truncated is true, and aggregation uses the first 5000. The cap is not the only reason for this flag: it also appears when fewer records were read than reported by data.count; the shortfall is in data.meta.recordsShortfall.

Boolean grouping fields. groupBy: "payed" or groupBy: "canceled" returns groups with true / false values.

The truncation flag appears alongside the number. When the response has meta.truncated: true, a truncated: true flag appears inside each field object in data.aggregates and on each item in data.groups, and a warning with the AGGREGATE_TRUNCATED code is added to data.meta.warnings. This lets a client reading only the number see that it was calculated from a subset of records. A complete response has none of these flags. For the full explanation, see Aggregation POST — the 5000-record ceiling.

See also