Conversations
The inbox: one row per contact, unread first, each contact's thread across every channel, and its read / starred / archived state.
The inbox: one row per contact, unread first, each contact's thread across every channel, and its read / starred / archived state.
Every route takes Authorization: Bearer <ACCESS_TOKEN> unless the auth line says otherwise. Ids are numbers. Errors use the shape on the errors page.
| Route | Scope | What it does |
|---|---|---|
GET /v1/conversations | conversations.read | Every conversation in a workspace, unread first, then newest first. |
GET /v1/conversations/{contact_id}/messages | conversations.read | A contact's thread, newest first, on every channel. |
GET /v1/conversations/{contact_id}/state | conversations.read | Read, starred, archived, AI paused and DND for one contact's conversation. |
PATCH /v1/conversations/{contact_id}/state | conversations.write | Mark a conversation read or unread, star or unstar it, archive or restore it, pause or resume the AI. |
List conversations
GET https://api.bluereacher.com/v1/conversationsAuth: Bearer access token. Scope: conversations.read.
Every conversation in a workspace, unread first, then newest first.
One row per contact (or group chat). unread_count and is_read are the same as in the Blue Reacher inbox. Filters combine with AND.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspace_id | query | number | yes | The workspace. |
page | query | number | no | Default 1. |
limit | query | number | no | 1–50, default 20. Anything else is a 400. |
search | query | string | no | Name or number. |
unread | query | boolean | no | 1 = unread only. |
starred | query | boolean | no | 1 = starred only. |
archived | query | boolean | no | 1 = archived only. |
Request
curl -X GET "https://api.bluereacher.com/v1/conversations?workspace_id=7&page=1&limit=20" \
-H "Authorization: Bearer <ACCESS_TOKEN>"Responses
A 200 reply (OK):
{
"success": true,
"data": [
{
"contact_id": 1234,
"name": "Ann Lee",
"phone": "+61412345678",
"is_group": false,
"group_id": null,
"channels": [],
"last_message": "Is Tuesday still OK?",
"last_message_at": "2026-10-27T09:12:43.000Z",
"last_inbound_at": "2026-10-27T09:12:43.000Z",
"last_outbound_at": "2026-10-26T15:02:10.000Z",
"unread_count": 1,
"is_read": false,
"is_starred": false,
"is_archived": false
}
],
"pagination": {
"page": 1,
"limit": 20,
"max_limit": 50,
"total": 128,
"total_pages": 7,
"unread_total": 9
}
}| Status | When | Message |
|---|---|---|
| 200 | OK | |
| 401 | Missing or invalid token | Invalid or expired access token. |
| 403 | Missing scope | Missing scope(s): conversations.read. This integration was granted: … |
| 404 | Workspace does not exist or is not owned by the installer (same response for both) | Workspace not found or not accessible to this token |
List conversation messages
GET https://api.bluereacher.com/v1/conversations/{contact_id}/messagesAuth: Bearer access token. Scope: conversations.read.
A contact's thread, newest first, on every channel.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
contact_id | path | number | yes | The contact id. |
page | query | number | no | Default 1. |
limit | query | number | no | 1–100, default 50. Anything else is a 400. |
Request
curl -X GET "https://api.bluereacher.com/v1/conversations/1234/messages?page=1&limit=50" \
-H "Authorization: Bearer <ACCESS_TOKEN>"Responses
A 200 reply (OK):
{
"success": true,
"data": {
"contact_id": 1234,
"workspace_id": 7,
"messages": [
{
"id": 84214,
"direction": "outbound",
"channel": "imessage",
"status": "delivered",
"message": "✦ Effect: confetti\nHappy birthday, Ann!",
"effect": "confetti",
"reaction": null,
"attachments": [],
"error_message": null,
"sent_at": "2026-10-27T09:15:00.000Z",
"delivered_at": "2026-10-27T09:15:02.000Z",
"created_at": "2026-10-27T09:15:00.000Z"
},
{
"id": 84215,
"direction": "inbound",
"channel": "imessage",
"status": "received",
"message": "❤️ Loved: “Happy birthday, Ann!”",
"effect": null,
"reaction": {
"kind": "love",
"emoji": "❤️",
"snippet": "Happy birthday, Ann!"
},
"attachments": [],
"error_message": null,
"sent_at": null,
"delivered_at": null,
"created_at": "2026-10-27T09:16:10.000Z"
}
]
},
"pagination": {
"page": 1,
"limit": 50,
"max_limit": 100,
"total": 37,
"total_pages": 1
}
}| Status | When | Message |
|---|---|---|
| 200 | OK | |
| 401 | Missing or invalid token | Invalid or expired access token. |
| 403 | Missing scope | Missing scope(s): conversations.read. This integration was granted: … |
| 404 | Contact does not exist or is not owned by the installer (same response for both) | Contact not found or not accessible to this token |
Get conversation state
GET https://api.bluereacher.com/v1/conversations/{contact_id}/stateAuth: Bearer access token. Scope: conversations.read.
Read, starred, archived, AI paused and DND for one contact's conversation.
thread is the key the conversation lives under: the contact's phone number, or the email of an email-only iMessage contact. unread_count counts inbound messages since last_read_at; is_unread is the manual "mark as unread" flag; is_read is false when either applies — the same three the inbox shows. is_ai_paused is the contact's AI toggle (also on Get contact / Update contact), and dnd the same object as Get DND.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
contact_id | path | number | yes | The contact id. |
Request
curl -X GET "https://api.bluereacher.com/v1/conversations/1234/state" \
-H "Authorization: Bearer <ACCESS_TOKEN>"Responses
A 200 reply (OK):
{
"success": true,
"data": {
"contact_id": 1234,
"workspace_id": 7,
"thread": "+61412345678",
"unread_count": 1,
"is_read": false,
"is_unread": false,
"is_starred": true,
"is_archived": false,
"last_read_at": "2026-10-27T08:00:00.000Z",
"archived_at": null,
"is_ai_paused": false,
"dnd": {
"outbound": {
"all": false,
"channels": []
},
"inbound": {
"all": false,
"channels": []
}
}
}
}| Status | When | Message |
|---|---|---|
| 200 | OK | |
| 401 | Missing or invalid token | Invalid or expired access token. |
| 403 | Missing scope | Missing scope(s): conversations.read. This integration was granted: … |
| 404 | Contact does not exist or is not owned by the installer (same response for both) | Contact not found or not accessible to this token |
Update conversation state
PATCH https://api.bluereacher.com/v1/conversations/{contact_id}/stateAuth: Bearer access token. Scope: conversations.write.
Mark a conversation read or unread, star or unstar it, archive or restore it, pause or resume the AI.
Send any of the four flags; the rest are left as they are. is_unread: false marks the conversation read (the unread count drops to 0); is_unread: true marks it unread the way the inbox does — one unread, and the chat is marked unread in Messages on the workspace's Advanced-Mode line too. Archiving hides the conversation from the inbox's main list (it is still returned with archived=1) and never deletes messages. is_ai_paused is the same as sending it on Update contact: the AI agent stops replying to this contact until it is resumed, and Contact Updated automations hear about it. A contact with neither a phone number nor an email has no conversation, so read / star / archive answer 400 for it; the AI flag still works.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
contact_id | path | number | yes | The contact id. |
is_unread | body | boolean | no | false = mark read, true = mark unread. |
is_starred | body | boolean | no | Star / unstar. |
is_archived | body | boolean | no | Archive / restore. |
is_ai_paused | body | boolean | no | Pause / resume the AI agent for this contact. |
Request
curl -X PATCH "https://api.bluereacher.com/v1/conversations/1234/state" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"is_unread": false,
"is_starred": true
}'Responses
A 200 reply (OK — the state afterwards):
{
"success": true,
"message": "Conversation updated",
"data": {
"contact_id": 1234,
"workspace_id": 7,
"thread": "+61412345678",
"unread_count": 0,
"is_read": true,
"is_unread": false,
"is_starred": true,
"is_archived": false,
"last_read_at": "2026-11-04T03:10:00.000Z",
"archived_at": null,
"is_ai_paused": false,
"dnd": {
"outbound": {
"all": false,
"channels": []
},
"inbound": {
"all": false,
"channels": []
}
}
}
}| Status | When | Message |
|---|---|---|
| 200 | OK — the state afterwards | |
| 400 | No flag, a non-boolean, or a contact with no phone or email | Send at least one of is_unread, is_starred, is_archived, is_ai_paused. |
| 401 | Missing or invalid token | Invalid or expired access token. |
| 403 | Missing scope | Missing scope(s): conversations.write. This integration was granted: … |
| 404 | Contact does not exist or is not owned by the installer (same response for both) | Contact not found or not accessible to this token |

