GET
/api/public/v1/conversations/{conversationId}

Get a conversation

One conversation in full: its members, topic and description, the caller’s own read state, and the latest message. Readable by the same rule as its messages. A member always can; a public channel of the caller’s own company can be read without joining, and the support rota can read a Support channel. Without a membership there is no read state, so `isMember` is false and `unreadCount`, `unreadThreadCount`, `lastReadAt`, `markedUnread`, `isMuted` and `isFavorite` are null — never somebody else’s. A conversation outside the caller’s reach is a 404, the same as one that does not exist, so an id cannot be probed. An archived channel is readable only with `threads:admin`. `members` carries names and roles only — not login addresses or presence.

Required scope

The access token must carry this scope. A token missing it gets 403 Forbidden. Grant them to an API client under Dev Tools → API, to an assistant or CLI sign-in when you approve or edit it under Dev Tools, and to a teammate under Employee → Permissions.

threads:read

Path Parameters

NameTypeRequiredDescription
conversationIdstringRequiredConversation ID.
GETExample request
curl
curl -X GET "https://www.pxb.app/api/public/v1/conversations/{conversationId}" \
  -H "Authorization: Bearer your_access_token"
200Example response
json
{
  "message": "Conversation retrieved successfully!",
  "content": {
    "conversation": {
      "id": "cnv_5150",
      "referenceId": 88,
      "type": "CHANNEL",
      "title": "engineering",
      "name": "engineering",
      "topic": "Shipping things",
      "description": null,
      "visibility": "PUBLIC",
      "isArchived": false,
      "lastMessageAt": "2026-08-29T18:22:00.000Z",
      "isSupport": false,
      "isCrossCompany": false,
      "memberEmployeeIds": [
        "emp_12ab",
        "emp_44f1"
      ],
      "createdAt": "2026-01-08T09:00:00.000Z",
      "isMember": true,
      "unreadCount": 3,
      "unreadThreadCount": 1,
      "lastReadAt": "2026-08-29T17:58:00.000Z",
      "markedUnread": false,
      "isMuted": false,
      "isFavorite": true,
      "members": [
        {
          "employeeId": "emp_12ab",
          "name": "Joseph Hall",
          "role": "ADMIN",
          "isExternal": false,
          "isDeactivated": false
        },
        {
          "employeeId": "emp_44f1",
          "name": "Ada Reyes",
          "role": "MEMBER",
          "isExternal": false,
          "isDeactivated": false
        }
      ],
      "latestMessage": {
        "id": "msg_9931",
        "conversationId": "cnv_5150",
        "authorEmployeeId": "emp_12ab",
        "parentMessageId": null,
        "content": "Deploying the billing export now — <@emp_44f1> heads up.",
        "type": "TEXT",
        "replyCount": 2,
        "lastReplyAt": "2026-08-29T18:22:00.000Z",
        "unreadReplyCount": 1,
        "editedAt": null,
        "deletedAt": null,
        "pinnedAt": null,
        "attachments": [],
        "reactions": [],
        "mentions": [
          {
            "employeeId": "emp_44f1"
          }
        ],
        "createdAt": "2026-08-29T18:10:00.000Z",
        "preview": "Deploying the billing export now"
      }
    }
  }
}
403Example response
json
{
  "message": "You are not a member of this conversation."
}
404Example response
json
{
  "message": "Conversation not found."
}

In the console

The same thing done by hand, for anyone comparing the API against the screen they already use.

Threads
/threads
  1. Open a conversation from the sidebar.