For AI agents: markdown of this page — /docs-content-en/entities/shipment-items/aggregate.md documentation index — /llms.txt
Aggregate shipment items
POST /v1/shipment-items/aggregate
Counts shipment items and computes the sum, average, minimum and maximum of the product quantity, with filtering and grouping by shipment or basket item.
Standard fields
| Field | Purpose |
|---|---|
Fieldquantity |
PurposeProduct quantity in the item — the main field for sum / avg / min / max. Also available for groupBy |
FieldreservedQuantity |
PurposeReserved quantity — a numeric field for sum / avg / min / max and groupBy |
FieldorderDeliveryId |
PurposeShipment ID from GET /v1/shipments — used in groupBy to break items down by shipment |
FieldbasketId |
PurposeBasket item ID from GET /v1/basket-items — used in groupBy to break items down by basket product |
The fields allowed in groupBy are listed in the aggregatable array of GET /v1/shipment-items/fields. Numeric functions accept any field of type number from the same schema, including id, which is outside aggregatable.
User fields. If you pass a nonexistent field to sum / avg / min / max, the 400 INVALID_PARAMS response lists the allowed numeric fields. That list contains only the standard shipment item fields — basketId, id, orderDeliveryId, quantity, reservedQuantity. It contains no user fields.
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
Fieldaggregate |
Typearray | Requiredno | DescriptionArray of expressions { "field": "quantity", "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/shipment-items/fields.Filtering syntax. Example: { "orderDeliveryId": 985 } |
FieldgroupBy |
Typestring | string[] | Requiredno | DescriptionA field or array of fields to group by, up to 5 fields. Allowed values come from the aggregatable array: quantity, reservedQuantity, orderDeliveryId, basketId |
FieldgroupOrderBy |
Typearray | Requiredno | DescriptionGroup sorting: [{ "field": "quantity:sum", "direction": "desc" }]. The field takes count, a field name from groupBy, or <field>:<function> from aggregate. Works only together with groupBy |
FieldgroupLimit |
Typenumber | Requiredno | DescriptionLimit on 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/shipment-items/aggregate" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": { "orderDeliveryId": { "$in": [975, 985] } },
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "quantity", "function": "sum" },
{ "field": "quantity", "function": "avg" }
],
"groupBy": "orderDeliveryId"
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/shipment-items/aggregate" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"filter": { "orderDeliveryId": { "$in": [975, 985] } },
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "quantity", "function": "sum" },
{ "field": "quantity", "function": "avg" }
],
"groupBy": "orderDeliveryId"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { orderDeliveryId: { $in: [975, 985] } },
aggregate: [
{ field: '*', function: 'count' },
{ field: 'quantity', function: 'sum' },
{ field: 'quantity', function: 'avg' },
],
groupBy: 'orderDeliveryId',
}),
})
const { success, data } = await res.json()
// data.groups — product quantity per shipment
console.log(data.groups)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/aggregate', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
filter: { orderDeliveryId: { $in: [975, 985] } },
aggregate: [
{ field: '*', function: 'count' },
{ field: 'quantity', function: 'sum' },
{ field: 'quantity', function: 'avg' },
],
groupBy: 'orderDeliveryId',
}),
})
const { success, data } = await res.json()
To group by several fields, pass an array: "groupBy": ["orderDeliveryId", "basketId"], up to 5 fields.
Other scenarios
The blocks below are request bodies.
Only the number of items in a shipment — without the aggregate array no records are loaded, and data.meta.recordsProcessed in the response is 0:
{ "filter": { "orderDeliveryId": 985 } }
Shipments with the largest product quantity — the first two groups by descending sum of quantity:
{
"aggregate": [{ "field": "quantity", "function": "sum" }],
"groupBy": "orderDeliveryId",
"groupOrderBy": [{ "field": "quantity:sum", "direction": "desc" }],
"groupLimit": 2
}
Total and maximum product quantity across all items, without grouping:
{
"aggregate": [
{ "field": "*", "function": "count" },
{ "field": "quantity", "function": "sum" },
{ "field": "quantity", "function": "max" }
]
}
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata.count |
Typenumber | DescriptionNumber of shipment items matching the filter |
Fielddata.aggregates |
Typeobject | DescriptionResults of numeric functions by field: { "quantity": { "sum": 16, "avg": 5.33 } }. An empty object if aggregate contains only count: the count result comes in data.count and data.groups[].count, not here |
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 records processed, 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 shortfall is reported in data.meta.recordsShortfall, and the interrupted slice in data.meta.pageErrorSample. Always present, false on a complete response. If the request has neither groupBy nor numeric functions, no records are loaded 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": 3,
"aggregates": {
"quantity": {
"sum": 16,
"avg": 5.333333333333333
}
},
"groups": [
{
"orderDeliveryId": 975,
"count": 1,
"aggregates": {
"quantity": {
"sum": 1,
"avg": 1
}
}
},
{
"orderDeliveryId": 985,
"count": 2,
"aggregates": {
"quantity": {
"sum": 15,
"avg": 7.5
}
}
}
],
"meta": {
"totalRecords": 3,
"recordsProcessed": 3,
"truncated": false,
"groupTotal": 2,
"groupsTruncated": false
}
}
}
Without groupBy, the data.groups, data.meta.groupTotal and data.meta.groupsTruncated fields are absent from the response.
Error response example
400 — the field is not in the schema, and the message lists the allowed numeric fields:
{
"success": false,
"error": {
"code": "INVALID_PARAMS",
"message": "Field 'weight' not found. Available numeric fields: basketId, id, orderDeliveryId, quantity, reservedQuantity."
}
}
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 contains 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 xmlId — 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 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, for example xmlId — the message contains the list of allowed ones |
| HTTP400 | CodeINVALID_PARAMS |
DescriptiongroupBy contains 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 the value of one of them is invalid |
| HTTP400 | CodeUNKNOWN_FILTER_FIELD |
DescriptionUnknown field in filter — the message contains the list of shipment item fields |
| HTTP400 | CodeINVALID_FILTER_FIELD |
DescriptionA field name in filter starts with the unsupported prefix @ or !@ |
| HTTP400 | CodeINVALID_FILTER_OPERATOR |
DescriptionUnsupported operator in filter or a logical condition, for example $or |
| HTTP400 | CodeINVALID_FILTER_SHAPE |
Descriptionfilter is not passed as an object of conditions, for example as a string |
| HTTP400 | CodeINVALID_DUPLICATE_FILTER_FIELD |
DescriptionTwo filter conditions reduce to one Bitrix24 condition, for example $ne and $nin on the same field. Pass one of them |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe API key lacks the sale scope |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is missing |
| HTTP401 | CodeTOKEN_MISSING |
DescriptionThe API key has no configured tokens |
| HTTP429 | CodeRATE_LIMITED |
DescriptionRequest limit exceeded: 300 per minute per portal, and all API keys of the portal share one limit. The current limit is returned in the x-ratelimit-limit header. Retry after the period 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 runs as a single request to Bitrix24 — no records are loaded, and the response time does not depend on the number of items. As soon as the request contains sum / avg / min / max or groupBy, including together with a single count, records are loaded page by page, at most 5000, and aggregated on the Vibecode side. With meta.truncated: true, the truncated: true marker is set both inside each field object 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 result set, use a request without groupBy and numeric functions, or narrow the filter, for example by orderDeliveryId. For full details, see Aggregation POST — the 5000-record ceiling.
The count includes items of the system shipment. The selection includes the same records as the item list, including items of the system shipment, which holds the unallocated remainder of the basket. Therefore, the sum of quantity for a basket item without a shipment filter equals the product quantity in the basket. To count only what has been shipped, filter by the orderDeliveryId of shipments from GET /v1/shipments.