Messaging
Marking inbound messages as read
Update WhatsApp read state using a stable Yanola inbound message ID.
What this guide covers
- Use the msg_ identifier from an inbound event or message log.
- Only inbound messages can be marked as read.
- Treat repeated read operations as safe application behavior.
Use a Yanola inbound message ID
Call markAsRead with the public ID from an inbound message log or webhook event. Live IDs start with msg_ and Test Mode IDs start with msg_test_. Raw provider message IDs are not accepted.
The key needs messages:write and access to the inbound message's Sender. The message must belong to the same Yanola Account, Agent Project, and environment as the key.
Mark the latest inbound message
This example lists a message first, so the key needs both messages:read and messages:write. If your webhook already supplies the Yanola message ID, call markAsRead directly with that ID.
import { WhatsAppClient } from "@yanola/whatsapp"
const apiKey = process.env.YANOLA_API_KEY
if (!apiKey) {
throw new Error("Missing YANOLA_API_KEY")
}
const yanola = new WhatsAppClient({ apiKey })
const { data: messages } = await yanola.messages.list({
direction: "inbound",
limit: 1,
})
const inbound = messages[0]
if (!inbound) {
throw new Error("No inbound message was found")
}
const result = await yanola.messages.markAsRead(inbound.id)
console.log(result.status) // "read"Mode-specific behavior
| Behavior | Test Mode | Live Mode |
|---|---|---|
Accepted ID | Same-environment msg_test_ inbound ID | Same-environment msg_ inbound ID |
Provider call | No | Yes, when the message was not already read |
Stored state | Synthetic message becomes read | Inbound public message becomes read after provider acceptance |
Repeated call | Returns read again | Returns read without another provider call when already read |
REST request
The REST operation is POST /v1/messages/{messageId}/mark-read and does not accept a request body.
curl --request POST \
"https://api.yanola.ai/v1/messages/msg_.../mark-read" \
--header "Authorization: Bearer $YANOLA_API_KEY" \
--header "Accept: application/json"{
"id": "msg_...",
"status": "read",
"requestId": "req_..."
}Mark-as-read errors
| Status and code | Meaning | Action |
|---|---|---|
400 invalid_message_id | The path does not contain a Yanola msg_ or msg_test_ public ID. | Use the ID from a Yanola inbound record or event. |
400 invalid_message_request | A request body was supplied. | Send an empty POST request. |
403 sender_access_denied | The key is restricted from the message's Sender. | Use an allowed key or update Sender access. |
404 message_not_found | The message is outbound, missing, inaccessible, or belongs to the other environment. | Do not substitute a provider ID; check the key environment and message source. |
422 sender_reconnect_required | The associated Sender cannot perform the live provider operation. | Reconnect the Sender in Yanola. |
503 mark_read_provider_unavailable / rejected | The live provider call failed transiently or was rejected. | Retry only when the error has retryable: true. |
Idempotent read state
Mark-as-read is naturally idempotent: once the message is read, repeating the call returns the same public message ID and read state. This operation does not use the SDK's automatic send idempotency key.