> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pilotstatus.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /v1/messages/read — Mark Messages as Read

> Send a WhatsApp read receipt (blue ticks) for a contact's last inbound message, without sending a message.

# Mark Messages as Read

```text theme={null}
POST https://pilotstatus.com.br/v1/messages/read
```

Sends a WhatsApp **read receipt** (double blue tick) for the **last inbound message** of the conversation with `to` — marking that message and every earlier one as read **without sending a message**.

<Note>
  Best-effort: the request is accepted (`200`) even when there is nothing to confirm — check the `acked` field in the response.
</Note>

## Headers

* `Content-Type: application/json`
* `x-api-key: ps_...` (or `x-api-key-id: <api_key_id>`) — a **number-scoped** key

## Body

<ParamField body="to" type="string" required>
  Destination phone in **E.164** or bare digits (e.g. `+5511999999999` or `5511999999999`) — the contact whose inbound messages to mark read.
</ParamField>

## Example

```bash theme={null}
curl -X POST "https://pilotstatus.com.br/v1/messages/read" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ps_your_key_here" \
  -d '{ "to": "5511999999999" }'
```

## Response (200)

```json theme={null}
{ "ok": true, "acked": true }
```

<ResponseField name="ok" type="boolean">
  Always `true` when the request was accepted.
</ResponseField>

<ResponseField name="acked" type="boolean">
  `true` when a read receipt was dispatched to the provider; `false` when there was nothing to confirm — see `reason`.
</ResponseField>

<ResponseField name="reason" type="string">
  Present only when `acked` is `false`:

  * `NO_INBOUND_MESSAGE` — the conversation has no inbound message to acknowledge.
  * `PII_RELAY_ONLY` — the number's privacy mode is RELAY\_ONLY, so no inbound id is stored.
</ResponseField>

## Provider behavior

| Provider                              | How it works                                                                                                             |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **Meta Cloud API**                    | Cloud API `status:"read"` on the last inbound message (marks it and every earlier message read).                         |
| **Evolution (Pilot Status web / GO)** | Native `POST /message/markread` through a connected instance. Evolution V2 has no read-receipt endpoint → `acked:false`. |

## Common errors

| Status | Meaning                                                                                    |
| ------ | ------------------------------------------------------------------------------------------ |
| `400`  | Invalid JSON, missing `to`, or the key is not bound to a number (`code: NUMBER_NOT_FOUND`) |
| `401`  | Missing/invalid API key header (`x-api-key` / `x-api-key-id`)                              |
| `403`  | A tenant-scoped key used on a number-scoped endpoint                                       |
| `404`  | No conversation with `to` (`code: CONVERSATION_NOT_FOUND`)                                 |
