# POST /api/v1/inboxes/:id/messages/batch-update

Auth: Bearer

HTML: https://cooperemail.com/docs/reference/batch-update-messages

## Summary

Add or remove the same labels on 1 to 50 messages. Body is message_ids plus add_labels and/or remove_labels. At least one label list must be non-empty (400 missing_labels). An empty message_ids array is 400 missing_message_ids. Duplicate ids are 400 duplicate_message_ids. More than 50 ids are 400 too_many_ids. read and unread can change. Other system labels return protected_label, invalid_label, or label_conflict, the same as PATCH on one message. Ids that are not in this inbox are omitted. The messages that are in this inbox all update, or none do. Returns {object:"list", limit, count, data} with full message JSON in request order. limit is the number of ids in the request. count is how many updated. Works on a paused inbox. A held message keeps the held label and a withheld body. An inbox-scoped key for another inbox is 404 inbox_not_found. MCP: cooper_update_messages.

## Request

```json
{
  "message_ids": [
    "msg_a",
    "msg_b"
  ],
  "remove_labels": [
    "unread"
  ],
  "add_labels": [
    "read"
  ]
}
```

## Response

HTTP 200. Sample values illustrate the schema.

```json
{
  "object": "list",
  "limit": 1,
  "count": 1,
  "data": [
    {
      "id": "inb_example",
      "inbox_id": "inb_example",
      "thread_id": "thr_example",
      "direction": "inbound",
      "from": "ada@example.com",
      "to": [
        "string"
      ],
      "subject": "Hello",
      "text": "Tuesday works.",
      "html": "string",
      "extracted_text": "string",
      "extracted_html": "string",
      "preview": "string",
      "delivery_events": [
        {
          "type": "string",
          "recipient": "string",
          "created_at": "2026-10-18T12:00:00.000Z",
          "detail": "string"
        }
      ],
      "cc": [
        "string"
      ],
      "bcc": [
        "string"
      ],
      "reply_to": "string",
      "in_reply_to": "string",
      "references": [
        "string"
      ],
      "labels": [
        "string"
      ],
      "auth": {
        "spf": "string",
        "dkim": "string",
        "dmarc": "string"
      },
      "safety": {
        "score": 0,
        "verdict": "clean",
        "signals": [
          {
            "type": null,
            "detail": null
          }
        ],
        "mode": "off",
        "reason": "string"
      },
      "provider": "string",
      "client_id": "inb_example",
      "idempotent": true
    }
  ]
}
```

## Errors

- HTTP 400 missing_labels
- HTTP 400 missing_message_ids
- HTTP 400 duplicate_message_ids
- HTTP 400 too_many_ids
- HTTP 404 inbox_not_found

The live `message` is the sentence for that code. Branch on `code`.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "missing_labels",
    "docs_url": "https://cooperemail.com/docs#missing_labels"
  }
}
```

## Idempotency

This route does not document Idempotency-Key or client_id.
