Skip to content

Conversations & Messages

Conversations are the core entity in HelperIQ — every customer thread is a conversation, regardless of channel (email, live chat, etc.). Messages belong to conversations. This page covers the full lifecycle.

Identifiers

  • uuid — the public conversation identifier, used in URLs and the agent UI. Stable forever.
  • reference_number — short integer ID for humans (#217). Shown in emails and the UI.
  • id — internal numeric primary key. Not used in URLs.

List conversations

All list endpoints share the same response shape (paginated, see API Introduction → Pagination) and accept the same filters / sorting / pagination query parameters.

MethodPathPermissionScope
GET/api/v1/conversations/allconversations:read_allEvery conversation visible to the caller
GET/api/v1/conversations/assignedconversations:read_assignedCaller's assigned tickets
GET/api/v1/conversations/unassignedconversations:read_unassignedTickets with no agent assignee
GET/api/v1/conversations/mentionedconversations:readTickets where the caller was @mentioned
GET/api/v1/conversations/spamconversations:read_allSpam bucket
GET/api/v1/conversations/trashconversations:read_allTrash bucket
GET/api/v1/teams/{id}/conversations/unassignedconversations:read_team_inboxTeam-inbox unassigned
GET/api/v1/views/{id}/conversationsconversations:readA saved view

Common query parameters:

ParamDefaultNotes
page11-indexed
page_size50Max 100
filtersJSON-encoded ad-hoc filter array (see API Introduction → Filtering)
order_bylast_message_atOne of: status_id, priority_id, assigned_team_id, assigned_user_id, inbox_id, last_message_at, last_interaction_at, created_at, waiting_since, next_sla_deadline_at, closed_at, resolved_at
orderdescasc or desc
statusesComma-separated status names (e.g. Open,Snoozed)

Response:

json
{
  "data": {
    "results": [
      {
        "uuid": "afa55a3b-…",
        "reference_number": 217,
        "subject": "Login problem after password reset",
        "status": "Open",
        "priority": "Medium",
        "assigned_user_id": 17,
        "assigned_team_id": 3,
        "inbox_id": 1,
        "contact": { "first_name": "Linda", "last_name": "Olsen", "email": "…" },
        "last_message_at": "2026-05-13T21:47:44Z",
        "waiting_since": null,
        "created_at": "2026-05-13T20:14:00Z"
      }
    ],
    "total": 16,
    "total_pages": 1,
    "page": 1,
    "page_size": 50
  }
}

Get one conversation

GET /api/v1/conversations/{uuid}                  conversations:read
GET /api/v1/conversations/by-ref/{ref}            conversations:read

by-ref looks up by reference_number instead of UUID — convenient for support agents who only have a ticket number to hand.

Create a conversation

POST /api/v1/conversations                        conversations:write

Used by the "New conversation" button to start an outbound thread.

Body:

FieldTypeDescription
inbox_idintWhich inbox to send from.
contactobject{ first_name, last_name, email } — created if not existing.
subjectstringInitial subject.
messagestringInitial outgoing message (HTML).
tostring[]Recipients. Defaults to the contact's email.
cc, bccstring[]Optional.
set_statusstringOptional — apply this status after send (deferred until SMTP succeeds).

Returns the created conversation row.

Update conversation fields

MethodPathPermission
PUT/api/v1/conversations/{uuid}/statusconversations:update_status
PUT/api/v1/conversations/{uuid}/priorityconversations:update_priority
PUT/api/v1/conversations/{uuid}/subjectconversations:update_status
PUT/api/v1/conversations/{uuid}/contactconversations:update_status
POST/api/v1/conversations/{uuid}/tagsconversations:update_tags
PUT/api/v1/conversations/{uuid}/custom-attributesauthenticated
PUT/api/v1/conversations/{uuid}/contacts/custom-attributesauthenticated

Status update body:

json
{ "status": "Resolved", "snoozed_until": null }

Snooze takes a Go duration string ("24h", "3d") — only required when status == "Snoozed".

Priority update body:

json
{ "priority": "High" }

Tags update body (replaces the full tag set):

json
{ "tags": ["billing", "vip"] }

Assignment

MethodPathPermission
PUT/api/v1/conversations/{uuid}/assignee/userconversations:update_user_assignee
PUT/api/v1/conversations/{uuid}/assignee/teamconversations:update_team_assignee
PUT/api/v1/conversations/{uuid}/assignee/user/removeconversations:update_user_assignee
PUT/api/v1/conversations/{uuid}/assignee/team/removeconversations:update_team_assignee

Body (user or team):

json
{ "assignee_id": 17 }

/remove endpoints take no body.

Trash, spam, merge, delete

MethodPathPermission
PUT/api/v1/conversations/{uuid}/trashconversations:update_status
PUT/api/v1/conversations/{uuid}/restoreconversations:update_status
PUT/api/v1/conversations/{uuid}/spamconversations:update_status
PUT/api/v1/conversations/{uuid}/not-spamconversations:update_status
POST/api/v1/conversations/mergeconversations:update_status
DELETE/api/v1/conversations/{uuid}conversations:update_status

Merge body:

json
{ "source_uuid": "abc-…", "target_uuid": "def-…" }

Moves all messages from source into target. source is then closed.

Delete is a permanent hard-delete — the conversation must be in the trash bucket first.

Read receipts + unread

MethodPathPermission
PUT/api/v1/conversations/{uuid}/last-seenconversations:read
PUT/api/v1/conversations/{uuid}/mark-unreadconversations:read

last-seen updates the caller's assignee_last_seen_at for collision indicators. The agent UI calls this on conversation focus.

Participants & followers

MethodPathPermission
GET/api/v1/conversations/{uuid}/participantsconversations:read
POST/api/v1/conversations/{uuid}/followauthenticated
DELETE/api/v1/conversations/{uuid}/followauthenticated
POST/api/v1/conversations/{uuid}/followersconversations:read
DELETE/api/v1/conversations/{uuid}/followers/{user_id}conversations:read

Detailed coverage of these on the Followers page.

Page visits (live chat)

GET /api/v1/conversations/{uuid}/page-visits      conversations:read

Returns the customer's recent page visits (livechat-only). Used by the "Pages visited" sidebar accordion on live-chat conversations.

Messages — list & read

GET /api/v1/conversations/{uuid}/messages         messages:read
GET /api/v1/conversations/{cuuid}/messages/{uuid} messages:read

The list endpoint accepts:

ParamDefaultDescription
page, page_size1, 50Standard pagination
typesComma-separated. E.g. incoming,outgoing to exclude activity log entries
privatetrue / false. Filters to private notes / public messages

Response (single message):

json
{
  "data": {
    "id": 12345,
    "uuid": "b29d68b1-…",
    "conversation_uuid": "afa55a3b-…",
    "type": "outgoing",
    "status": "sent",
    "private": false,
    "content_type": "html",
    "content": "<p>Hi Linda…</p>",
    "text_content": "Hi Linda…",
    "sender_id": 17,
    "sender_type": "agent",
    "created_at": "…",
    "meta": {}
  }
}

Send a message

POST /api/v1/conversations/{cuuid}/messages       messages:write

The agent reply endpoint. Powers both regular replies and forwards (see Forward for the extra forwarded_to field).

Body:

FieldTypeDescription
messagestringHTML body.
privatebooltrue for private notes (not sent to customer).
sender_typestringUsually agent.
to, cc, bccstring[]Recipients (email channel only).
fromstringOverride the inbox primary From. Must match the inbox's configured From or one of its aliases.
attachmentsobject[]Array of { media_uuid }. Upload via POST /api/v1/media first.
mentionsint[]Agent user IDs to mention (triggers in-app notifications).
set_statusstringOptional — apply this status after a successful send (gated on SMTP success). See Send-and-Close gating.
forwarded_tostring[]Forward mode — routes the message as a fresh email thread to these recipients instead of the conversation contact.

Response is the created message row.

Retry a failed message

PUT /api/v1/conversations/{cuuid}/messages/{uuid}/retry   messages:write

Re-queues a message in failed status. Only the original sender can retry. Powers the "Failed: retry?" affordance shown on failed message bubbles.

Private notes — edit / delete

PUT    /api/v1/conversations/{cuuid}/messages/{uuid}/note   messages:write
DELETE /api/v1/conversations/{cuuid}/messages/{uuid}/note   messages:write

Private notes are editable / deletable by the author only. Public messages (sent to the customer) are immutable.

PUT body:

json
{ "content": "<p>Updated note</p>" }

PCI redaction

POST /api/v1/conversations/{cuuid}/messages/{uuid}/redact   messages:write

Manually redact a message that contains PCI data flagged by the scrubber. Irreversible. See PCI Scrubbing for details.

Drafts

MethodPathPermission
GET/api/v1/draftsauthenticated
POST/api/v1/conversations/{uuid}/draftauthenticated
DELETE/api/v1/conversations/{uuid}/draftauthenticated

Drafts are per-(user × conversation). The agent UI auto-saves replies as drafts as you type.

Draft body:

json
{
  "content": "<p>Hi Linda…</p>",
  "private": false,
  "is_forward": false,
  "to": [], "cc": [], "bcc": [],
  "mentions": [],
  "macro_id": null
}

GET /api/v1/drafts returns all the caller's drafts across conversations — used to render the unsent-reply badge on the sidebar.

Apply a macro

POST /api/v1/conversations/{uuid}/macros/{id}/apply    authenticated

Applies the macro's actions (status change, tag, assignment, etc.) to the conversation. Returns the updated conversation row.

Macro content (the reply template) is inserted on the client side, not applied via this endpoint.

GET /api/v1/conversations/search and GET /api/v1/messages/search are covered on the Search page.

Released under AGPL-3.0. HelperIQ is a fork of LibreDesk.