Conversations
One thread per contact and number — the same data as the team inbox. Read history, reply, assign and resolve from your own systems.
EndpointsKey permission
- GET
/v1/conversationsList and filter conversationsinbox:read_all - GET
/v1/conversations/{id}inbox:read_all - PATCH
/v1/conversations/{id}Status, snooze, assignee, teaminbox:reply - GET
/v1/conversations/{id}/messagesMessage history, newest first (?before, ?limit)inbox:read_all - POST
/v1/conversations/{id}/messagesReply in the threadinbox:reply - POST
/v1/conversations/{id}/readMark read (sends blue ticks) → 204inbox:read_all - POST
/v1/conversations/{id}/typingShow a typing indicator → 204inbox:reply - GET
/v1/conversations/{id}/notesInternal notesinbox:read_all - POST
/v1/conversations/{id}/notes{ body } — up to 4,000 charactersinbox:reply - GET
/v1/canned-responsesSaved repliesinbox:reply - POST
/v1/canned-responses{ shortcut, title, body }inbox:reply
The conversation object
JSON
{
"id": "a81c…",
"status": "open",
"phone_number_id": "1c2d…",
"assignee": { "id": "2b9d…", "name": "John" },
"team_id": null,
"csw_expires_at": "2026-11-12T10:45:11Z",
"fep_expires_at": null,
"last_message_at": "2026-11-11T10:45:11Z",
"last_message_preview": "Is the blue one back in stock?",
"last_direction": "in",
"unread_count": 1,
"snoozed_until": null,
"bot_active": false,
"created_at": "2026-10-02T14:20:00Z",
"contact": { "id": "b1e7…", "name": "Jane Doe", "profile_name": "Jane", "phone": "14155550101", "username": null, "bsuid": "IN.1234567890", "opt_in": "opted_in" }
}Listing conversations
Query parameters
statusstringoptionalopen,pending,snoozed,resolvedorall.assigneestringoptionalme,unassigned,allor a user id.phone_number_iduuidoptionalOnly this number.contact_iduuidoptionalOnly this contact.taguuidoptionalContacts with this tag.unreadbooleanoptionaltruefor conversations with unread messages.qstringoptionalSearch contact name, profile name or phone.cursor, limitstring, integeroptionalPagination (30 by default, up to 100).
The response also contains counts per status, for building inbox tabs.
Messages in a conversation
GET /v1/conversations/{id}/messages returns message objects, newest first. To load older messages, pass the next_cursor from the previous page as before.
Replying
POST /v1/conversations/{id}/messages takes the same body as POST /v1/messages without the recipient fields — the conversation decides the contact and number. It honours Idempotency-Key and returns 202 with the full message object.
POST /v1/conversations/{id}/messages
JSON
{ "type": "text", "text": { "body": "Yes — the blue variant is back in stock!" } }Status and assignment
PATCH /v1/conversations/{id}
JSON
{ "status": "snoozed", "snoozed_until": "2026-11-12T04:30:00Z" }Fields: status, snoozed_until, assignee_id, team_id. Changing status needs inbox:reply; assigning needs inbox:assign. Each change fires conversation.updated.
Something unclear or missing on this page? Tell us at contact@swastik.ai