When to Use
- Chatbot inbound processing: An automated chatbot workflow marks every inbound customer message as read as soon as the WebhookTrigger receives it, ensuring customers see immediate acknowledgement even before a reply is generated.
- Agent-assigned ticket acknowledgement: A support ticketing workflow marks the customer's initial message as read when a human agent opens the ticket in the CRM, accurately reflecting that a real person has seen the message.
- Queue position confirmation: A contact centre workflow marks messages as read when they enter the agent queue, preventing customers from re-sending because they think their message was missed.
- Order status bot: A self-service order status workflow marks the enquiry message as read before querying the order database, giving the customer instant visual confirmation while the lookup runs.
- Compliance read receipt logging: A regulated financial services workflow marks advisement messages as read and logs the timestamp for compliance audit purposes, proving the customer's message was received and acted upon.
User experience impact: Sending a read receipt changes the message status icon for the sender from grey double ticks (delivered) to blue double ticks (read). Only call this operation when the message has actually been processed or is actively being handled — misleading read receipts reduce customer trust.
Configuration
Connection
| Field | Required | Description |
accessToken | Required | Permanent System User access token. Store in BizFirst Credentials Manager. |
phoneNumberId | Required | Numeric string ID of the receiving WhatsApp Business phone number (the number that received the message). |
apiVersion | Optional | Meta Graph API version. Defaults to v18.0. |
Operation
| Field | Required | Description |
messageId | Required | The WhatsApp message ID (wamid) of the inbound message to mark as read. Obtained from the webhook payload at entry[0].changes[0].value.messages[0].id. |
Sample Configuration
{
"resource": "message",
"operation": "markAsRead",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"messageId": "{{ $input.inboundMessageId }}"
}
Validation Errors
| Error | Cause |
accessToken is required | The accessToken field is empty. |
phoneNumberId is required | The phoneNumberId field is empty. |
messageId is required | The messageId field is empty. |
131026 (Meta) | The message ID is invalid or does not belong to this phone number's conversations. |
131047 (Meta) | The message is too old to mark as read (typically beyond 24 hours). |
Output
Success Port
| Field | Type | Description |
messageId | string | The message ID that was marked as read (echoed from input). |
status | string | "read" on success. |
errorCode | string | Empty on success. |
errorMessage | string | Empty on success. |
rawResponse | string | Full raw JSON from the Meta API. The API returns { "success": true } on success. |
Error Port
| Field | Type | Description |
messageId | string | The message ID that failed to be marked as read. |
status | string | "failed" or "error". |
errorCode | string | Meta error code or BizFirst validation code. |
errorMessage | string | Human-readable error description. |
rawResponse | string | Raw API error response. |
Sample Output
{
"messageId": "wamid.HBgLMTQxNTU1NTI2NzEVAgASGBI0QzM4NjhGQTExMjQ3RDMAA",
"status": "read",
"errorCode": null,
"errorMessage": null,
"rawResponse": "{\"success\":true}"
}
Expression Reference
| Value | Expression | Notes |
| Message ID | {{ $output.markRead.messageId }} | Echoed from input. Useful for chaining to confirm which message was marked. |
| Status | {{ $output.markRead.status }} | "read" on success. Use to confirm before proceeding with reply generation. |
| Error code | {{ $output.markRead.errorCode }} | Log on the error port for diagnostics. |
| Raw API result | {{ $output.markRead.rawResponse }} | Contains { "success": true } on a successful call. |
Node Policies & GuardRails
| Policy Area | Recommendation |
| Credential storage | Store the access token in BizFirst Credentials Manager. Never inline in configuration. |
| Timing | Call this operation as early as possible in the inbound message processing workflow — ideally as the very first node after the WebhookTrigger. Delayed read receipts may cause customers to believe their message was not received. |
| Message ID source | The messageId must be the wamid from the inbound webhook event, not a wamid from a previously sent outbound message. Marking an outbound message as read is a no-op and may return an error. |
| Do not mislead | Only call this operation when the message has been genuinely received and queued for processing. Do not mark messages as read from an unrelated automated batch if the content has not been examined. |
| Error handling | markAsRead failures are non-critical. Route errors to a logging node rather than a customer-facing error flow. The main workflow should proceed regardless of whether the read receipt was successfully sent. |
| Idempotency | Calling markAsRead multiple times on the same message ID is safe — the API is idempotent and returns success without error on duplicate calls. |
Examples
Immediate Acknowledgement on Webhook Trigger
{
"resource": "message",
"operation": "markAsRead",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"messageId": "{{ $trigger.entry[0].changes[0].value.messages[0].id }}"
}
This node is the first step in every inbound WhatsApp workflow after the WebhookTrigger. It immediately marks the customer's message as read (blue double ticks) before any processing logic runs. The 5-10ms API call provides a near-instant UX signal even when the full response takes several seconds to generate.
Agent Assignment Acknowledgement
{
"resource": "message",
"operation": "markAsRead",
"accessToken": "{{ $credentials.whatsAppToken }}",
"phoneNumberId": "123456789012345",
"messageId": "{{ $input.customerMessageId }}"
}
A CRM webhook fires when an agent opens a WhatsApp ticket. The workflow marks the original customer message as read at that moment, accurately reflecting that a human has reviewed the message. The customerMessageId is stored in the ticket record when the inbound message is first received.