For AI agents: markdown of this page — /docs-content-en/entities/shipments/aggregate.md documentation index — /llms.txt
Shipment aggregation
POST /v1/shipments/aggregate
Counts shipments and computes the sum, average, minimum and maximum of the delivery cost, with filtering and grouping by order or delivery service.
Standard fields
| Field | Purpose |
|---|---|
FieldpriceDelivery |
PurposeDelivery cost — the main field for sum / avg / min / max. Also available for groupBy |
FieldbasePriceDelivery, discountPrice |
PurposeBase delivery cost and delivery discount — numeric fields for sum / avg / min / max |
FieldorderId |
PurposeOrder ID — used in groupBy to break shipments down by order |
FielddeliveryId |
PurposeDelivery service ID — used in groupBy to break shipments down by service |
The fields available for groupBy are listed in the aggregatable array in GET /v1/shipments/fields. Numeric functions accept any field of type number from the same schema, including fields outside aggregatable.
User fields. For a non-existent field name in sum / avg / min / max, the 400 INVALID_PARAMS response lists the allowed numeric fields. That list contains only standard shipment fields — basePriceDelivery, companyId, deliveryId, discountPrice, empAllowDeliveryId, empCanceledId, empDeductedId, empMarkedId, empResponsibleId, id, orderId, priceDelivery, responsibleId, with no user fields. A rejection for a field outside aggregatable in groupBy names only orderId, priceDelivery, deliveryId as allowed.
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
Fieldaggregate |
Typearray | Requiredno | DescriptionArray of expressions { "field": "priceDelivery", "function": "sum" }, up to 5 per request. Functions: count, sum, avg, min, max. For count the field is "*". Without the parameter, only count is returned |
Fieldfilter |
Typeobject | Requiredno | DescriptionFiltering by the fields of GET /v1/shipments/fields.Filtering syntax. Example: { "orderId": 1027 } |
FieldgroupBy |
Typestring | string[] | Requiredno | DescriptionA field or an array of fields to group by, up to 5 fields. Allowed values come from the aggregatable array: orderId, priceDelivery, deliveryId |
FieldgroupOrderBy |
Typearray | Requiredno | DescriptionGroup sorting: [{ "field": "priceDelivery:sum", "direction": "desc" }]. field accepts count, a field name from groupBy, or <field>:<function> from aggregate. Works only together with groupBy |
FieldgroupLimit |
Typenumber | Requiredno | DescriptionLimits the number of returned groups, from 1 to 1000. Works only together with groupBy |
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/shipments/aggregate" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": { "orderId": 1027 },
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "priceDelivery", "function": "sum" },
{ "field": "priceDelivery", "function": "avg" }
],
"groupBy": "deliveryId"
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/shipments/aggregate" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": { "orderId": 1027 },
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "priceDelivery", "function": "sum" },
{ "field": "priceDelivery", "function": "avg" }
],
"groupBy": "deliveryId"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/shipments/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { orderId: 1027 },
aggregate: [
{ field: '*', function: 'count' },
{ field: 'priceDelivery', function: 'sum' },
{ field: 'priceDelivery', function: 'avg' },
],
groupBy: 'deliveryId',
}),
})
const { success, data } = await res.json()
// data.groups — delivery cost by delivery service
console.log(data.groups)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/shipments/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { orderId: 1027 },
aggregate: [
{ field: '*', function: 'count' },
{ field: 'priceDelivery', function: 'sum' },
{ field: 'priceDelivery', function: 'avg' },
],
groupBy: 'deliveryId',
}),
})
const { success, data } = await res.json()
Other scenarios
The blocks below are request bodies.
Shipment count for an order only — without the aggregate array no records are fetched, and data.meta.recordsProcessed in the response is 0:
{ "filter": { "orderId": 1027 } }
Grouping by two fields — by order and delivery service:
{
"aggregate": [{ "field": "*", "function": "count" }],
"groupBy": ["orderId", "deliveryId"]
}
Sum and average of the delivery cost without grouping:
{
"filter": { "orderId": 1027 },
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "priceDelivery", "function": "sum" },
{ "field": "priceDelivery", "function": "avg" }
]
}
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata.count |
Typenumber | DescriptionNumber of shipments matching the filter |
Fielddata.aggregates |
Typeobject | DescriptionResults of numeric functions by field: { "priceDelivery": { "sum": 500, "avg": 500 } }. An empty object if aggregate contains only count |
Fielddata.groups |
Typearray | DescriptionPresent only with groupBy. Each element holds the grouping field values, count and aggregates for the group |
Fielddata.meta.totalRecords |
Typenumber | DescriptionTotal number of records matching the filter |
Fielddata.meta.recordsProcessed |
Typenumber | DescriptionNumber of processed records, up to 5000 |
Fielddata.meta.truncated |
Typeboolean | Descriptiontrue if the numbers were not computed over all records matching 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 subpage error. The size of the shortfall arrives in data.meta.recordsShortfall, the cut-short slice in data.meta.pageErrorSample. Always present, false on a complete response. If the request has neither groupBy nor numeric functions, no records are fetched and the flag is always false |
Fielddata.meta.groupTotal |
Typenumber | DescriptionPresent only with groupBy — the number of groups before groupLimit is applied |
Fielddata.meta.groupsTruncated |
Typeboolean | DescriptionPresent only with groupBy. true if the group list was cut by groupLimit |
Response example
{
"success": true,
"data": {
"count": 1,
"aggregates": {
"priceDelivery": {
"sum": 500,
"avg": 500
}
},
"groups": [
{
"deliveryId": 1,
"count": 1,
"aggregates": {
"priceDelivery": {
"sum": 500,
"avg": 500
}
}
}
],
"meta": {
"totalRecords": 1,
"recordsProcessed": 1,
"truncated": false,
"groupTotal": 1,
"groupsTruncated": false
}
}
}
Error response example
400 — the field is not in the schema. The message lists the allowed numeric fields:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "Field 'weight' not found. Available numeric fields: basePriceDelivery, companyId, deliveryId, discountPrice, empAllowDeliveryId, empCanceledId, empDeductedId, empMarkedId, empResponsibleId, id, orderId, priceDelivery, responsibleId."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | CodeINVALID_PARAMS |
Descriptioncount is passed with a field other than "*" |
| HTTP400 | CodeINVALID_PARAMS |
Descriptionaggregate is passed as a non-array or an empty array |
| HTTP400 | CodeINVALID_PARAMS |
Descriptionaggregate has more than 5 expressions |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionUnknown function — the message lists the allowed ones |
| HTTP400 | CodeINVALID_PARAMS |
Descriptionsum / avg / min / max without a field or with the field "*" |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionThe field for sum / avg / min / max is not numeric, for example trackingNumber — the message names its type |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionThe field for sum / avg / min / max is not in the schema — the message contains the list of numeric fields |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionThe op, field or function fields are passed at the top level of the body instead of the aggregate array |
| HTTP400 | CodeINVALID_PARAMS |
DescriptiongroupBy is neither a string nor an array of strings |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionA field in groupBy is outside the aggregatable array — the message contains the list of allowed ones |
| HTTP400 | CodeINVALID_PARAMS |
DescriptiongroupBy has more than 5 fields |
| HTTP400 | CodeINVALID_PARAMS |
DescriptiongroupBy contains a reserved name: count, aggregates, meta, groups |
| HTTP400 | CodeINVALID_PARAMS |
DescriptiongroupOrderBy or groupLimit is passed without groupBy, or its value is invalid |
| HTTP400 | CodeUNKNOWN_FILTER_FIELD |
DescriptionUnknown field in filter — the message contains the list of shipment fields |
| HTTP400 | CodeINVALID_FILTER_FIELD |
DescriptionA field name in filter starts with the unsupported prefix @ or !@ |
| HTTP400 | CodeINVALID_FILTER_OPERATOR |
DescriptionUnsupported operator in filter, an empty object in a condition value, or the $or logical condition |
| HTTP400 | CodeINVALID_FILTER_SHAPE |
Descriptionfilter is not an object of conditions, for example a string, a number or an array |
| HTTP400 | CodeINVALID_DUPLICATE_FILTER_FIELD |
DescriptionTwo filter conditions reduce to one Bitrix24 condition, for example $ne and $nin on the same field. Pass only one of them |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe API key has no sale scope |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is not passed |
| 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. A request without groupBy and without numeric functions is handled by a single request to Bitrix24 — no records are fetched, and the response time does not depend on the number of shipments. As soon as the request has sum / avg / min / max or groupBy, including together with a single count, up to 5000 records are loaded page by page, and the aggregates are computed by Vibecode. With meta.truncated: true, the truncated: true mark is also set inside the object of each field in data.aggregates and on each element of data.groups, and data.meta.warnings carries the AGGREGATE_TRUNCATED warning. For an exact number on a large selection, use a request without groupBy and numeric functions, or narrow the filter, for example by orderId. For a full explanation, see Aggregation POST — the 5000-record ceiling.