For AI agents: markdown of this page — /docs-content-en/entities/doc-templates/aggregate.md documentation index — /llms.txt
Aggregate document templates
POST /v1/doc-templates/aggregate
Count and numeric aggregations (sum, average, minimum, maximum) over document templates with filtering and grouping.
Standard fields:
sort— sort index, the only numeric field wheresum/avg/min/maxare meaningfulnumeratorId— numerator, a number, works in numeric functions and ingroupByfileId— template file on Drive, a number, works in numeric functions and ingroupByregion— template region, a string, forgroupByonlymoduleId— owner module, a string, forgroupByonlyactive— active flag, a string, forgroupByonly
The sum/avg/min/max functions accept only numeric fields — those of type number in GET /v1/doc-templates/fields. A string field in a numeric function returns 400 INVALID_PARAMS. groupBy accepts any field from the list above.
Request fields (body)
| Parameter | Type | Required | Description |
|---|---|---|---|
aggregate |
array | no | Array of aggregations. Each item: { "field": "sort", "function": "sum" }. Functions: count, sum, avg, min, max. For count the field is "*". Without the array — count only |
filter |
object | no | Filtering by the fields from GET /v1/doc-templates/fields. Filtering syntax |
groupBy |
string | string[] | no | A field or an array of fields to group by (up to 5). Allowed values are from the list above |
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/doc-templates/aggregate" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"aggregate": [
{ "field": "sort", "function": "sum" },
{ "field": "sort", "function": "avg" }
],
"groupBy": "region"
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/doc-templates/aggregate" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"aggregate": [
{ "field": "sort", "function": "sum" },
{ "field": "sort", "function": "avg" }
],
"groupBy": "region"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/doc-templates/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
aggregate: [
{ field: 'sort', function: 'sum' },
{ field: 'sort', function: 'avg' },
],
groupBy: 'region',
}),
})
const { success, data } = await res.json()
console.log('Total templates:', data.count)
console.log('By region:', data.groups)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/doc-templates/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
aggregate: [
{ field: 'sort', function: 'sum' },
{ field: 'sort', function: 'avg' },
],
groupBy: 'region',
}),
})
const { success, data } = await res.json()
To group by several fields, pass an array:
"groupBy": ["region", "active"](up to 5).
Other scenarios
Record count — count with the field "*", the fastest request without loading templates. Without the aggregate array the result is the same:
{ "aggregate": [{ "field": "*", "function": "count" }] }
Breakdown by two fields at once — how many templates fall into each combination of region and active flag:
{ "groupBy": ["region", "active"] }
Number of templates in a single region — count with a filter, records are not loaded:
{ "filter": { "region": "uk" } }
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.count |
number | Total number of templates matching the filter |
data.aggregates |
object | Numeric aggregation results: { "sort": { "sum": 1650, "avg": 275 } }. An empty object when the aggregate array is not passed |
data.groups |
array | Groups, present only with groupBy. Each item: grouping fields + count + aggregates |
data.meta.totalRecords |
number | Total number of records matching the filter |
data.meta.recordsProcessed |
number | How many records were processed for numeric aggregations. Equals 0 for a request without numeric functions — records are not loaded |
data.meta.truncated |
boolean | true when the numbers were computed over only some of the records that match the filter: fewer records were read than data.count promised — including when more than 5000 matched the filter — or the slice was cut short by a sub-page error. The size of the gap is reported in data.meta.recordsShortfall, the interrupted slice in data.meta.pageErrorSample. Always present, and false on a complete response. If the request has neither groupBy nor a numeric function, no records are fetched and the flag is always false |
data.meta.groupTotal |
number | Number of groups, present only with groupBy |
data.meta.groupsTruncated |
boolean | true if there were more groups than the output limit. Present only with groupBy |
Response example
Response to the main request (sum and avg over sort with groupBy: "region"):
{
"success": true,
"data": {
"count": 6,
"aggregates": {
"sort": { "sum": 1650, "avg": 275 }
},
"groups": [
{
"region": "uk",
"count": 3,
"aggregates": { "sort": { "sum": 600, "avg": 200 } }
},
{
"region": "de",
"count": 2,
"aggregates": { "sort": { "sum": 900, "avg": 450 } }
},
{
"region": "fr",
"count": 1,
"aggregates": { "sort": { "sum": 150, "avg": 150 } }
}
],
"meta": {
"totalRecords": 6,
"recordsProcessed": 6,
"truncated": false,
"groupTotal": 3,
"groupsTruncated": false
}
}
}
Without groupBy the fields data.groups, data.meta.groupTotal and data.meta.groupsTruncated are absent from the response.
Error response example
400 — a non-existent field. The message lists the available fields:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "Field 'bogus' not found. Available numeric fields: id, numeratorId, sort, fileId, createdBy, updatedBy."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_PARAMS |
Invalid function name or a non-existent field — the message lists the available fields |
| 400 | INVALID_PARAMS |
A string field (region, moduleId, active) in sum/avg/min/max — the message names the field type |
| 400 | INVALID_PARAMS |
groupBy on a field outside the list, a reserved word (count, aggregates, meta, groups), or more than 5 fields in groupBy |
| 403 | SCOPE_DENIED |
The API key lacks the documentgenerator scope |
| 401 | TOKEN_MISSING |
The API key has no configured tokens |
| 429 | RATE_LIMITED |
Rate limit exceeded: 300 requests per minute per portal, all API keys of the portal share one limit. The exact value arrives in the x-ratelimit-limit header (the cap is divided across replicas). Retry after the delay in the Retry-After header |
For the full list of common API errors, see Errors.
Known specifics
count vs numeric functions. count is computed with a single call to Bitrix24 for any data volume, without loading records, and meta.recordsProcessed equals 0. The sum/avg/min/max functions load records page by page (up to 5000) and compute on the Vibecode side — if more than 5000 records match the filter, meta.truncated becomes true and the aggregation runs over the first 5000. For exact counts on large result sets, use count or narrow the filter. The ceiling is not the only reason for this marker: it also appears when fewer records were read than data.count promised, and the size of the gap is reported in data.meta.recordsShortfall.
Numeric aggregation is over a single field. Only sort yields a meaningful sum or average. The numeratorId and fileId fields are numeric too and are accepted in sum/avg/min/max, but they are identifiers — aggregate them for grouping, not for summation. The remaining fields are strings and work only in groupBy.
The truncation marker travels with the number itself. When a response arrives with meta.truncated: true, the marker truncated: true sits inside every field object in data.aggregates and on every element of data.groups, and data.meta.warnings gains a warning with the code AGGREGATE_TRUNCATED. A client that reads only the number itself therefore sees that it was computed over only some of the records. None of these markers appear on a complete response. Full details — Aggregation POST — the 5000-record ceiling.