---
title: "Batch operate on messages by id"
method: POST
path: "/messages/batch"
tags: ["messages"]
---

# Batch operate on messages by id

`POST /messages/batch`

## Request

- Base URL: `https://dash.mailsocket.app/api/v1`
- URL: `https://dash.mailsocket.app/api/v1/messages/batch`
- Auth: HTTP bearer

Applies one `action` (`mark_read` | `delete` | `fetch`) across up to
100 of your message ids in one call. An id that does not exist and an
id owned by another account both return `status: not_found`.
Requires a paid plan (`402 plan_upgrade_required` on Free). The body
is validated before the plan check: a malformed body is always
`422 validation_error`, for every plan.
`mark_read` and `delete` are idempotent: repeating the call returns
the same shape without changing anything again. `Idempotency-Key`
applies to `mark_read` and `delete` only; it is ignored for `fetch`,
which always returns fresh data.

## Headers

- `Idempotency-Key` string

## Request body

- MessageBatchRequest
  - `action` 'mark_read' | 'delete' | 'fetch', required
  - `ids` string[], required: Message public ids. Duplicates are de-duplicated (order-preserving) before processing.

## Response `200`

Per-id results, in the same order as the input `ids`.

- MessageBatchResponse
  - `data` object, required
    - `results` MessageBatchResultItem[], required: Same order as the input `ids`.
      - `id` string, required
      - `status` 'ok' | 'deleted' | 'not_found', required
      - `message` Message: Full message representation: `MessageSummary` minus `has_html`, plus `envelope_from`, `envelope_recipient`, `text` and `html`.
        - `id` string, required
        - `inbox_id` string, required
        - `from` string, required: The From header.
        - `to` string[], required
        - `cc` string[], required
        - `subject` string, required
        - `received_at` string, date-time, required
        - `status` 'received' | 'parsing' | 'parsed' | 'failed', required
        - `otp` string, nullable
        - `otp_confidence` number, nullable
        - `magic_link` string, nullable
        - `links` string[], nullable
        - `detected_otp` string, nullable
        - `otp_context` string, nullable: A short (≤160 character) plain-text snippet around `otp`; null when no OTP or not locatable.
        - `otp_candidates` object[], nullable: Ranked plausible codes beyond the primary `otp`; null/empty when only one or none.
          - `code` string, required
          - `confidence` number, required
        - `provider_hint` string, nullable: Best-effort sending-service label from the From domain; null when unknown.
        - `envelope_from` string, required
        - `envelope_recipient` string, required
        - `text` string, required: The plain-text body.
        - `html` string, required: The sanitized HTML body.
        - `read` boolean: Whether the message has been marked read (`read_at IS NOT NULL`).
        - `metadata` object, required: The owning inbox's `metadata` (`{}` when unset). Present in poll/latest/wait/batch fetch AND the webhook delivery payload (which is this exact schema).

## Other responses

- `400`: The `Idempotency-Key` header is empty, longer than 255 characters, or not printable ASCII, or the request body is too large to read with an `Idempotency-Key`.
- `401`: Missing or invalid API key.
- `402`: The account is on the Free plan and this operation needs a paid plan (`plan_upgrade_required`). Upgrade, then retry.
- `403`: Account is not permitted to use the API.
- `409`: A request with the same `Idempotency-Key` is still running (`idempotency_in_progress`).
- `422`: `validation_error` — the body does not match `MessageBatchRequest` (checked before the plan, so Free callers see it too); or `idempotency_key_reused` — the same `Idempotency-Key` was used with a different request.
- `429`: Rate limit exceeded.

---

[API](https://skmtc.dev/mailsocket/apis/mailsocket-api.md) · [All operations](https://skmtc.dev/mailsocket/apis/mailsocket-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mailsocket/apis/mailsocket-api/revisions/e579500dfb7e?raw)
