## Search shipment items

`POST /v1/shipment-items/search`

Searches online store order shipment items with filtering, sorting, and automatic pagination. Parameters are passed in the body of the POST request. Suited to complex filters and wide date ranges. For simple selections of up to 5000 records, the shipment item list is enough.

## Request fields (body)

| Field | Type | Required | Default | Description |
|------|-----|:-----:|-----------|---------|
| `filter` | object | no | — | Filtering by the fields from `GET /v1/shipment-items/fields`.<br>[Filtering syntax](/docs/filtering). Example: `{ "basketId": 1387 }` |
| `select` | string[] | no | — | Field selection: `["id", "orderDeliveryId", "quantity"]`. A comma-separated string is also accepted. An unknown field does not cause an error: it is absent from the `data` items, and `meta.warnings` carries an `UNKNOWN_SELECT_FIELD` warning with the field name in `field` |
| `sort` | string | no | — | Sorting via the short syntax: `"-id"`, where a leading minus means descending |
| `order` | object | no | — | Sorting as an object: `{ "id": "asc" }`. If `sort` is also passed, `sort` takes effect |
| `limit` | number | no | `50` | Number of records, from 1 to 5000. A value above 5000 is reduced to 5000 without an error |
| `offset` | number | no | `0` | Skip N records. Rejected when combined with a date range filter wider than 14 days, unless `autoWindow: false` is passed — see `UNSTABLE_OFFSET_PAGINATION` in the "Errors" section |
| `autoWindow` | boolean | no | `true` | Split the selection into weekly windows when filtering by a `dateInsert` range wider than 14 days. `false` disables splitting |
| `withTotal` | boolean | no | — | Whether to return the record count in `meta.total`. Details — [Paging and record counts](/docs/entity-api#paging-and-record-counts) |

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/shipment-items/search" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": { "basketId": 1387 },
    "select": ["id", "orderDeliveryId", "quantity"],
    "order": { "id": "asc" }
  }'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/shipment-items/search" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": { "basketId": 1387 },
    "select": ["id", "orderDeliveryId", "quantity"],
    "order": { "id": "asc" }
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/search', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    filter: { basketId: 1387 },
    select: ['id', 'orderDeliveryId', 'quantity'],
    order: { id: 'asc' },
  }),
})

const { success, data, meta } = await res.json()
for (const item of data) {
  console.log(`Shipment ${item.orderDeliveryId}: ${item.quantity}`)
}
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/shipment-items/search', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    filter: { basketId: 1387 },
    select: ['id', 'orderDeliveryId', 'quantity'],
    order: { id: 'asc' },
  }),
})

const { success, data, meta } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | array | Array of shipment items |
| `data[].id` | number | Shipment item identifier |
| `data[].orderDeliveryId` | number | Shipment ID. List: [`GET /v1/shipments`](/docs/entities/shipments/list) |
| `data[].basketId` | number | Basket item ID. List: [`GET /v1/basket-items`](/docs/entities/basket-items/list) |
| `data[].quantity` | number | Product quantity in the shipment, may be fractional |
| `data[].reservedQuantity` | number | Reserved quantity |
| `data[].xmlId` | string | External code of the item |
| `data[].dateInsert` | datetime | Creation date, ISO 8601 |
| `meta.total` | number | How many records matched the filter. May be absent — see the `withTotal` field |
| `meta.hasMore` | boolean | Whether there are more records beyond `limit` |
| `meta.durationMs` | number | Request duration in milliseconds |
| `meta.autoWindowed` | boolean | `true` if the selection was split into time windows |
| `meta.windowCount` | number | Number of windows. Arrives with `autoWindowed: true` |
| `meta.windowErrors` | number | How many windows ended with an error. Arrives if some of the windows failed |
| `meta.windowErrorSample` | object | Error code and message of the first failed window. Arrives together with `windowErrors` |
| `meta.batchWaves` | number | Number of waves of parallel requests. Arrives with `autoWindowed: true` |
| `meta.warnings` | array | Warnings about request parameters: `code`, `message`, `field`. Arrives only when there are warnings |
| `meta.hint` | string | Advice to narrow the date range or disable splitting. Arrives if the search went through more than 10 windows and took longer than 10 seconds |
| `meta.pageErrorSample` | object | Code and message of the error that stopped automatic pagination early. Arrives only if `data` holds fewer records than `limit` |

## Response example

A request with `select` returns only the listed fields:

```json
{
  "success": true,
  "data": [
    {
      "id": 1347,
      "orderDeliveryId": 1195,
      "quantity": 0.25
    },
    {
      "id": 1353,
      "orderDeliveryId": 1207,
      "quantity": 0.75
    }
  ],
  "meta": {
    "total": 2,
    "hasMore": false,
    "durationMs": 342
  }
}
```

## Error response example

400 — filter by a nonexistent field:

```json
{
  "success": false,
  "error": {
    "code": "UNKNOWN_FILTER_FIELD",
    "message": "Unknown filter field 'foo' for entity 'shipment-items'. Available: basketId, dateInsert, id, orderDeliveryId, quantity, reservedQuantity, xmlId"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `UNKNOWN_FILTER_FIELD` | Filter by a field that is not in the schema. Field list: [`GET /v1/shipment-items/fields`](/docs/entities/shipment-items/fields) |
| 400 | `INVALID_FILTER_FIELD` | The field name in the filter starts with the unsupported prefix `@` or `!@` |
| 400 | `INVALID_FILTER_OPERATOR` | Unknown filter operator, an empty object as a condition value, or the logical condition `$or` |
| 400 | `INVALID_FILTER_SHAPE` | `filter` is not an object of conditions, for example a string, number, or array |
| 400 | `INVALID_DUPLICATE_FILTER_FIELD` | Two filter conditions reduce to one Bitrix24 condition, for example `$ne` and `!=` on the same field. Pass only one of them |
| 400 | `UNKNOWN_SORT_FIELD` | Sorting by a field that is not in the schema |
| 400 | `INVALID_SORT_TYPE` | `sort` or `order` has an unsupported type, for example a number |
| 400 | `INVALID_SORT_DIRECTION` | The direction in `order` or in the object form of `sort` is not one of `asc`, `desc`, `ASC`, `DESC`, `1`, `-1` |
| 400 | `INVALID_LIMIT` | `limit` is not a number |
| 400 | `INVALID_SELECT_TYPE` | `select` is not a string or an array of strings |
| 400 | `INVALID_REQUEST` | The request body is not a JSON object |
| 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset` greater than zero together with a filter by a date range wider than 14 days. Fetch everything in one request with `limit` up to 5000, or pass `autoWindow: false` with sorting by `id`, or split the date range into parts yourself |
| 403 | `SCOPE_DENIED` | The API key does not have the `sale` scope |
| 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | The request was made with a management key. Entities require an application key or a personal key with the `sale` scope |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is missing |
| 401 | `INVALID_API_KEY` | The API key passed was not found |
| 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 |

Full list of common API errors — [Errors](/docs/errors).

## Known specifics

**Splitting into time windows.** With windows, the selection gets past the cap of 5000 records per call. A range from January 1, 2025 to October 8, 2026 was split into 93 windows processed in three waves: `meta.windowCount: 93`, `meta.batchWaves: 3`. The same request with `autoWindow: false` returned the same 104 records in a single pass.

**A partial window failure does not abort the request.** If some of the windows failed, the response arrives with `success: true` and records only from the successful windows. Before treating the selection as complete, check that `meta.windowErrors` is absent.

## See also

- [List shipment items](/docs/entities/shipment-items/list)
- [Get a shipment item](/docs/entities/shipment-items/get)
- [Shipment item aggregation](/docs/entities/shipment-items/aggregate)
- [Shipment item fields](/docs/entities/shipment-items/fields)
- [Shipment items](/docs/entities/shipment-items)
- [Filtering syntax](/docs/filtering)
- [Entity reference](/docs/entity-api)
- [Limits and optimization](/docs/optimization)
