## Batch operations

`POST /v1/recurring-deals/batch`

Runs several operations of the same type on recurring deal settings.

## Parameters

There are no path parameters. The batch payload is passed in the request body.

## Request fields (body)

| Field | Type | Required | Description |
|---|---|---|---|
| `action` | string | yes | Operation for the whole batch: `create`, `update`, `delete`, `list`, `get` or `fields` |
| `items` | object[] | no | Required for `create` and `update`. A non-empty array of objects with [create](./create.md) or [update](./update.md) fields |
| `items[].id` | number / string | no | Required for `update`. Setting ID from the [recurring deals list](./list.md) |
| `ids` | array | no | Required for `delete`. A non-empty array of setting IDs from the [recurring deals list](./list.md) |
| `calls` | object[] | no | Required for `list`, `get` and `fields`. A non-empty array of subrequests |
| `calls[].params` | object | no | Subrequest parameters. For `list` — [list parameters](./list.md), for `get` — the setting ID, for `fields` you can pass `{}` |
| `calls[].params.id` | number / string | no | Required for `get`. Setting ID from the [recurring deals list](./list.md) |

The batch size is limited by platform settings. By default, up to 500 items for `create`, `update`, `delete` and up to 50 subrequests for `list`, `get`, `fields`.

In write batches, `null` is not passed for `active`, `startDate`, `categoryId`, `limitRepeat`, `limitDate` and the nested `params` fields. To pass `null` explicitly, use [create a single setting](./create.md) or [update a single setting](./update.md).

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/recurring-deals/batch" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action":"update","items":[{"id":11,"active":false}]}'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/recurring-deals/batch" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"update","items":[{"id":11,"active":false}]}'
```

### JavaScript — personal key

```javascript
const response = await fetch('https://vibecode.bitrix24.com/v1/recurring-deals/batch', {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({"action":"update","items":[{"id":11,"active":false}]}),
})
const result = await response.json()
if (!result.success) throw new Error(result.error.message)
console.log(result.data)
```

### JavaScript — OAuth application

```javascript
const response = await fetch('https://vibecode.bitrix24.com/v1/recurring-deals/batch', {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({"action":"update","items":[{"id":11,"active":false}]}),
})
const result = await response.json()
if (!result.success) throw new Error(result.error.message)
console.log(result.data)
```

## Response fields

### Create, update and delete

| Field | Type | Required | Description |
|---|---|---|---|
| `success` | boolean | yes | `true` if the batch is processed. Check the result of each item separately |
| `data` | object | yes | Batch results |
| `data.results` | object[] | yes | Results in the order of the request items |
| `data.results[].index` | number | yes | Zero-based index of the item in the source array |
| `data.results[].success` | boolean | yes | Whether the operation on this item succeeded |
| `data.results[].id` | number / string | no | ID of the created setting, or the source ID on update and delete. Get the setting: [by ID](./get.md) |
| `data.results[].error` | string | no | Refusal code of the item. Can be an empty string, so check `success` |
| `data.results[].message` | string | no | Refusal message of the item |
| `data.summary` | object | yes | Batch summary |
| `data.summary.total` | number | yes | Number of processed items |
| `data.summary.succeeded` | number | yes | Number of successful operations |
| `data.summary.failed` | number | yes | Number of refused operations |

An error in a single operation is returned in `data.results`, and the HTTP status of the batch stays `200`.

### Read

| Field | Type | Required | Description |
|---|---|---|---|
| `success` | boolean | yes | `true` if the batch is processed |
| `data` | object[] | yes | Results in the order of the subrequests |
| `data[].data` | object / array / null | no | Successful result: for `list` — an array of settings, for `get` — a setting or `null`, for `fields` — a map of field metadata. Setting fields: [Recurring deal fields](./fields.md) |
| `data[].total` | number | no | Total number of records for `list` |
| `data[].hasMore` | boolean | no | Whether there is a next page for `list` |
| `data[].meta` | object | no | List warnings |
| `data[].error` | object | no | Refusal of a single subrequest instead of `data` |
| `data[].error.code` | string | no | Refusal code of the subrequest |
| `data[].error.message` | string | no | Refusal message of the subrequest |

For `fields`, the map keys keep the original Bitrix24 field names, for example `ID` and `DEAL_ID`. For `list` and `get`, the setting fields use Vibecode API names.

A refusal of one read subrequest does not stop the rest. The HTTP status of the batch stays `200`.

## Response example

200 — the setting from the example is updated:

```json
{
  "success": true,
  "data": {
    "results": [
      {
        "index": 0,
        "success": true,
        "id": 11
      }
    ],
    "summary": {
      "total": 1,
      "succeeded": 1,
      "failed": 0
    }
  }
}
```

For reads the structure differs. Request body: `{"action":"list","calls":[{"params":{"filter":{"id":11},"select":["id","active"]}}]}`.

```json
{
  "success": true,
  "data": [
    {
      "data": [
        {
          "id": 11,
          "active": false
        }
      ],
      "total": 1,
      "hasMore": false
    }
  ]
}
```

## Error response example

400 — an unknown operation is passed:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_BATCH_ACTION",
    "message": "Action must be one of: create, update, delete, list, get, fields"
  }
}
```

## Errors

The table describes refusals of the whole request. Refusals of individual operations are in the batch results.

Write batches have no rollback. If the request fails after commands have been sent, for example with `502 BITRIX_UNAVAILABLE` or `503 BITRIX_TIMEOUT`, some operations may have completed and the outcome of others may be unknown. The error response does not include the accumulated successful results. Check the state of the records before retrying: repeating a create request may produce duplicates.

| HTTP | Code | Description |
|---|---|---|
| 400 | `INVALID_BATCH_ACTION` | `action` is missing or an unknown operation is passed |
| 400 | `BATCH_ITEM_VALIDATION` | No non-empty array is passed for the selected operation, a required item field is missing, or an item contains an invalid value or a read-only field |
| 400 | `BATCH_LIMIT_EXCEEDED` | The batch size limit is exceeded. The current limit is given in `error.message` |
| 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | A management key has no access to entity data |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key passed the scope check, but its mode forbids `create`, `update` or `delete` |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is not passed |
| 401 | `TOKEN_MISSING` | No Bitrix24 access tokens are configured |
| 403 | `SCOPE_DENIED` | The key lacks the `crm` scope |
| 403 | `BITRIX_ACCESS_DENIED` | Bitrix24 denied access to the whole batch |
| 422 | `BITRIX_ERROR` | A Bitrix24 business refusal at the level of the whole batch. The reason is in `error.message` |
| 503 | `BITRIX_TIMEOUT` | Bitrix24 did not respond in time |
| 502 | `BITRIX_UNAVAILABLE` | A network failure or a Bitrix24 server error with HTTP status 500 and above |
| 429 | `RATE_LIMITED` | The request limit is exceeded. The wait time is in the `Retry-After` header |

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

## See also

- [Create a setting](./create.md)
- [Update a setting](./update.md)
- [Delete a setting](./delete.md)
- [Recurring deals](../recurring-deals.md)
- [Batch](/docs/batch)
- [MCP for AI](/docs/mcp)
- [Deals](../deals.md)
