Read State & Inbox
Track per-participant read receipts and query the inbox with unread counts.
Mark as Read
POST /api/v1/threads/:threadId/read
{
"participantExternalId": "usr-abc",
"participantRole": "GUEST",
"messageId": "msg-005"
}
If messageId is omitted, the latest message in the thread is used. Upserts the read state -- safe to call repeatedly.
Get Read States
GET /api/v1/threads/:threadId/read-state
Returns read state for all participants in the thread:
{
"success": true,
"data": {
"readStates": [
{
"participantId": "tp-guest",
"participant": { "role": "GUEST", "externalId": "usr-abc", "displayName": "Ade Bakare" },
"lastReadMessageId": "msg-005",
"lastReadAt": "2026-04-12T10:05:00.000Z"
}
]
}
}
Inbox
The inbox is a convenience endpoint that returns all threads for a participant with unread counts and last message preview. Powers consumer-side inbox UIs.
Get Inbox
GET /api/v1/threads/inbox?externalId=usr-abc&role=GUEST
Query parameters:
externalId(required) -- the participant's ID in your applicationrole(required) -- the participant's rolestatus(optional) -- filter by thread status (OPEN,CLOSED,ARCHIVED)page,limit(optional) -- pagination
Response:
{
"success": true,
"data": {
"items": [
{
"thread": { "id": "th-001", "entityId": "BK-2026-00451", "subject": "...", "status": "OPEN", "messageCount": 5 },
"channel": { "slug": "booking", "displayName": "Booking Conversations", "entityType": "BOOKING" },
"unreadCount": 2,
"lastMessage": { "id": "msg-005", "content": "Check-in is from 2pm.", "type": "TEXT", "createdAt": "..." }
}
],
"total": 1
}
}
Get Unread Count
GET /api/v1/threads/inbox/unread-count?externalId=usr-abc&role=GUEST
Returns the total unread message count across all open threads:
{ "success": true, "data": { "count": 3 } }