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
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
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
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
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:
{ "aggregate": [{ "field": "*", "function": "count" }] }
Sum across all orders without grouping:
{
"aggregate": [{ "field": "price", "function": "sum" }]
}
Top 3 statuses by order total, with sorting:
{
"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
{
"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:
{
"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.