For AI agents: markdown of this page — /docs-content-en/entities/shipment-items/batch.md documentation index — /llms.txt
Batch operations on shipment items
POST /v1/shipment-items/batch
Create, update, delete or read shipment items in bulk with one request — up to 500 items per write and up to 50 calls per read. This is a dedicated endpoint for this entity, not to be confused with the universal batch, which combines operations on different entities and is limited to 50 calls.
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | yes | Batch operation: create, update, delete for writes, list, get for reads. One request performs one operation |
items |
array | yes for create and update |
List of items, up to 500 |
items[].orderDeliveryId |
number | yes for create |
Shipment ID. List: GET /v1/shipments. Not passed in update — the field is read-only |
items[].basketId |
number | yes for create |
ID of a basket item of the same order. List: GET /v1/basket-items. Not passed in update — the field is read-only |
items[].quantity |
number | yes | Product quantity in the shipment; a fractional value is stored without rounding. Required both in create and in every update item. An update item without quantity does not reject the batch — it fails inside a 200 response |
items[].xmlId |
string | no | External code |
items[].id |
number | yes for update |
Shipment item ID. List: GET /v1/shipment-items |
ids |
number[] | yes for delete |
IDs of the shipment items to delete, up to 500. List: GET /v1/shipment-items |
calls |
array | yes for list and get |
List of read calls, up to 50. Each call is an object { "params": { … } } |
calls[].params |
object | yes | For list — the item list parameters: filter, select, limit, offset. For get — { "id": 1363 } |
The field set of an items element matches the body of POST /v1/shipment-items and PATCH /v1/shipment-items/:id. The full list of item fields is in GET /v1/shipment-items/fields.
The create body is in the "Examples" section. Bodies of the other operations:
update—{ "action": "update", "items": [{ "id": 1363, "quantity": 0.75 }] }delete—{ "action": "delete", "ids": [1363] }list—{ "action": "list", "calls": [{ "params": { "filter": { "orderDeliveryId": 985 }, "limit": 50 } }] }get—{ "action": "get", "calls": [{ "params": { "id": 1363 } }] }
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/shipment-items/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "create",
"items": [
{ "orderDeliveryId": 1215, "basketId": 1387, "quantity": 0.5 }
]
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/shipment-items/batch" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "create",
"items": [
{ "orderDeliveryId": 1215, "basketId": 1387, "quantity": 0.5 }
]
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/batch', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'create',
items: [
{ orderDeliveryId: 1215, basketId: 1387, quantity: 0.5 },
],
}),
})
const { data } = await res.json()
data.results.forEach((item) => {
if (item.success) console.log(`#${item.index} → id=${item.id}`)
else console.log(`#${item.index} → error: ${item.error} ${item.message}`)
})
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/batch', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'create',
items: [
{ orderDeliveryId: 1215, basketId: 1387, quantity: 0.5 },
],
}),
})
const { data } = await res.json()
Response fields
The shape of data depends on the operation. For create, update and delete:
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true if the request passed validation as a whole. The result of each item is in data.results[i].success |
data.results |
array | Array of results in the same order as the request's items or ids |
data.results[].index |
number | Item index, starting from 0 |
data.results[].success |
boolean | Result of this operation |
data.results[].id |
number | ID of the shipment item — created, updated or deleted. Absent in a failed item |
data.results[].error |
string | Error code of a failed item, for example 201250000001 for a repeated basketId + orderDeliveryId pair |
data.results[].message |
string | Error text of a failed item |
data.summary.total |
number | Total items processed |
data.summary.succeeded |
number | How many succeeded |
data.summary.failed |
number | How many failed |
For list and get, the data field is an array of results in the order of calls, not an object with results. Each element carries either data or error. Here the error code is in the error object as error.code, while for writes it is a string in data.results[].error:
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true if the request passed validation as a whole |
data[].data |
array | object | null | For list — an array of items, for get — an item object or null. Item fields — Shipment item fields. With select, an item contains only the listed fields |
data[].total |
number | list only — number of items matching the call's filter |
data[].hasMore |
boolean | list only — whether there are items beyond limit and offset |
data[].error.code |
string | Error code of a failed call: CALL_FAILED for a non-existent id, INVALID_PARAMS for a non-integer id, a filter validation code for an invalid filter, for example UNKNOWN_FILTER_FIELD |
data[].error.message |
string | Error text of a failed call |
Response example
action: create — the item is created:
{
"success": true,
"data": {
"results": [
{ "index": 0, "success": true, "id": 1363 }
],
"summary": { "total": 1, "succeeded": 1, "failed": 0 }
}
}
action: create — the second item repeated the basketId + orderDeliveryId pair of the first one and failed, while the top-level success stayed true:
{
"success": true,
"data": {
"results": [
{ "index": 0, "success": true, "id": 1361 },
{
"index": 1,
"success": false,
"error": "201250000001",
"message": "Duplicate entry for key [basketId, orderDeliveryId]"
}
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
}
action: list — two calls for shipments 975 and 985 with the filter { "orderDeliveryId": { "$in": [975, 985] } }: the first with select: ["id", "orderDeliveryId", "quantity"], the second with limit: 1 and offset: 1:
{
"success": true,
"data": [
{
"data": [
{ "id": 875, "orderDeliveryId": 975, "quantity": 1 },
{ "id": 885, "orderDeliveryId": 985, "quantity": 10 },
{ "id": 887, "orderDeliveryId": 985, "quantity": 5 }
],
"total": 3,
"hasMore": false
},
{
"data": [
{
"basketId": 953,
"dateInsert": "2025-03-03T22:02:39.000Z",
"id": 885,
"orderDeliveryId": 985,
"quantity": 10,
"reservedQuantity": 0,
"xmlId": "bx_67c618efc3256"
}
],
"total": 3,
"hasMore": true
}
]
}
Error response example
400 — a create item lacks a required field, the whole batch is rejected:
{
"success": false,
"error": {
"code": "BATCH_ITEM_VALIDATION",
"message": "Item at index 0: field 'basketId' is required to create shipmentItem"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_BATCH_ACTION |
action is not passed or is not one of the allowed operations — the list comes in the error text |
| 400 | BATCH_ITEM_VALIDATION |
items, ids or calls is empty or not an array, or an items element is not an object |
| 400 | BATCH_ITEM_VALIDATION |
A create item lacks orderDeliveryId, basketId or quantity, or a read-only field is passed: id, dateInsert, reservedQuantity |
| 400 | BATCH_ITEM_VALIDATION |
An update item lacks id, has no field other than id, or a read-only field is passed: orderDeliveryId, basketId |
| 400 | BATCH_ITEM_VALIDATION |
A field value has the wrong type, for example an object in quantity — the message names the field and the expected type |
| 400 | BATCH_ITEM_VALIDATION |
An ID in ids or items[].id is not a non-negative integer, for example "1.5" |
| 400 | BATCH_LIMIT_EXCEEDED |
More than 500 elements in items or ids, or more than 50 calls in calls |
| 403 | SCOPE_DENIED |
The API key lacks the sale scope |
| 403 | WRITE_BLOCKED_READONLY_KEY |
create, update or delete with a read-only key — the batch is not executed |
| 403 | MANAGEMENT_KEY_NO_ENTITY_ACCESS |
Management key: entity sections are not available to it, a personal key or an OAuth application key is required |
| 401 | MISSING_API_KEY |
The X-Api-Key header is not passed |
| 401 | TOKEN_MISSING |
The API key has no configured tokens |
| 429 | RATE_LIMITED |
Rate limit exceeded: 30 requests per minute per portal (a batch costs more than a plain read), 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 |
A 400 response means the whole batch is rejected before any write. Errors of individual items come inside a 200 response: for writes — in data.results[i] as the error and message fields, for reads — in data[i].error. This is how, for example, an update item without quantity fails — with the error "Required fields: quantity".
Full list of common API errors — Errors.
Known specifics
An item of a system shipment is returned as null by get, and update on it fails. Unlike the single GET /v1/shipment-items/:id, which responds with 404, a get call in the batch returns { "data": null } without an error. An update element for such an item fails, just like the single PATCH, while the other items of the batch continue to be processed. For what a system shipment is, see Shipment items.