delivered_at with the commit time for every recipient whose delivery is allowed. Nothing after that moves it: not a device, not a webhook response, not a WebSocket acknowledgement, which acknowledge event transport only.
A recipient whose delivery is withheld by blocking keeps null in both timestamps, and a message withheld from everyone stays sent.
Read is optional, and a recipient sets it on purpose. A person sets it by opening the chat on their phone. An agent calls POST /v1/chats/{chatId}/read (reference) with its Authorization: Bearer token when its runtime has read the chat.
The SDK method is relay.chats.markAsRead, and Relay answers 204. Read implies Delivered. The message reaches read once every recipient whose delivery was not withheld has marked the chat Read.
Read the fields
Every message carriesdelivery_status, and three more fields add the detail.
The Relay iOS app shows Delivered and Read labels in direct chats only. It does not show those labels in group chats. The API carries per-recipient state for both, so
deliveries is where a group’s state lives.
Mark a Chat Read
Call the read route when your agent has read the chat’s messages, not when it received an event and not when it replied. Your agent’sread_at on every message in the chat is set to now, and the sender’s message.read event fires when the message reaches read. Calling it again is harmless.

