
## Batch comment operations

`POST /v1/tasks/:taskId/comments/batch`

Bulk create, update, or delete comments of a single task. Up to 50 items per call. Each item is processed independently — a failure of one does not cancel the rest.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|---------|
| `taskId` (path) | number | yes | Task ID |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|---------|
| `action` | string | ★ | Operation type: `create`, `update` or `delete` |
| `items` | array | for `create` / `update` | List of items (up to 50). For `create`: `[{ message: string }]`. For `update`: `[{ id: number, message: string }]` |
| `ids` | number[] | for `delete` | Comment identifiers to delete (up to 50) |

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/tasks/289/comments/batch" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "create",
    "items": [
      { "message": "Step 1: prepared the draft." },
      { "message": "Step 2: sent it for review." }
    ]
  }'
```

### curl — OAuth app

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/tasks/289/comments/batch" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "create",
    "items": [
      { "message": "Step 1: prepared the draft." },
      { "message": "Step 2: sent it for review." }
    ]
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/tasks/289/comments/batch', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    action: 'create',
    items: [
      { message: 'Step 1: prepared the draft.' },
      { message: 'Step 2: sent it for review.' },
    ],
  }),
})

const { success, data } = await res.json()
data.forEach((item) => {
  if (item.success) console.log(`#${item.index} → id=${item.id}`)
  else console.log(`#${item.index} → error: ${item.error}`)
})
```

### JavaScript — OAuth app

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/tasks/289/comments/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: [
      { message: 'Step 1: prepared the draft.' },
      { message: 'Step 2: sent it for review.' },
    ],
  }),
})

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

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` — even if every item failed, the top level is success. Check each item's status in `data[i]` |
| `data` | array | Array of results in the same order as the request `items` / `ids` |
| `data[].index` | number | Item index (0-based) |
| `data[].success` | boolean | Result of the specific operation |
| `data[].id` | number \| null | Comment ID on `create` / `update`. Occasionally `null` with `success: true` — the comment was created but its id wasn't recovered (see [`POST /v1/tasks/:taskId/comments`](./create.md) "Known specifics"). If Bitrix24 didn't create the comment at all (task doesn't exist/isn't accessible) that's a different case — `success: false` + `error: TASK_NOT_FOUND`, no id is returned |
| `data[].error` | string | Error code for a failed item (`GONE`, `BATCH_ITEM_VALIDATION`, `BITRIX_ERROR`, `INVALID_PARAMS`, `TASK_NOT_FOUND`) |
| `data[].message` | string | Error text for a failed item |

## Response example

`action: create` on the new card — both records went into the task chat:

```json
{
  "success": true,
  "data": [
    { "index": 0, "success": true, "id": 36571 },
    { "index": 1, "success": true, "id": 36573 }
  ]
}
```

`action: update` on the new card — every update attempt turns into `GONE` (method unavailable):

```json
{
  "success": true,
  "data": [
    {
      "index": 0,
      "success": false,
      "error": "GONE",
      "message": "Bitrix24 disabled update/delete for task comments in the new task card. To remove a comment, delete the source task or ask a portal admin to remove the message via the chat UI."
    }
  ]
}
```

## Error response example

400 — invalid `action` value:

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

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `INVALID_PARAMS` | `taskId` is not a positive integer |
| 400 | `INVALID_BATCH_ACTION` | `action` is not `create`, `update` or `delete` |
| 400 | `BATCH_ITEM_VALIDATION` | `items` (or `ids` for `delete`) is empty or not an array |
| 400 | `BATCH_LIMIT_EXCEEDED` | More than 50 items passed in a single request |
| 403 | `SCOPE_DENIED` | The API key does not have the `task` scope |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |

Errors of individual items arrive inside `data[i].error`:

| Code | Description |
|-----|----------|
| `GONE` | Only for `update` / `delete` on the new card — the operation is unavailable on the Bitrix24 side |
| `BATCH_ITEM_VALIDATION` | The item failed validation (for example, no `id` or `message`, wrong type) |
| `INVALID_PARAMS` | `message` is missing or exceeds the length limit |
| `BITRIX_ERROR` | Bitrix24 returned an error for the specific item (text in `message`) |
| `TASK_NOT_FOUND` | Only for `create` — task `taskId` doesn't exist or isn't accessible to the key, the comment was not created |

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

## Known specifics

**The top-level `success` is always `true` if the request passed validation.** Several failed items inside do not turn the whole response into an error — this is intentional so the client can handle a partial result. Before using the result, always check `data[i].success` for each item.

**`GONE` arrives per item separately.** On the new card, `update` / `delete` of each item returns `GONE`, but the overall response stays `200 success` — the whole batch is not rejected. In mixed scenarios, some items on the old card go through, others on the new card return `GONE`.

**`create` distinguishes "not created" from "created, id unknown".** If the task doesn't exist/isn't accessible, the item fails with `TASK_NOT_FOUND` (`success: false`, no `id`). If the comment was genuinely created (it went to the task's chat) but the system couldn't confirm its id via a search over recent messages, the item stays `success: true` with `id: null` — retrying will create a duplicate, not recover the original id.

## See also

- [Create comment](./create.md) — single POST
- [Update comment](./update.md) — single PATCH (same card contract)
- [Delete comment](./delete.md) — single DELETE
- [Universal batch](/docs/batch) — combining different entity operations into one HTTP call
- [Tasks](/docs/entities/tasks) — parent entity
