Conversations

Endpoints for listing, viewing, and updating real-time conversations between visitors and agents.

Overview

Conversations are the core entity in ZapTicket. Each conversation represents a real-time chat thread between a visitor and your support team. Conversations have a lifecycle (Open → Assigned → Closed) and can be filtered, assigned to agents, and converted into tickets.

💡All conversation endpoints require a workspace token. The tenant is automatically resolved from the JWT claims — you never pass a tenant ID manually.

Endpoints

List Conversations

GET/conversations

List conversations for the current workspace with optional filters and pagination.

Auth: Workspace token (agent)

Query Parameters
status       - Filter by status: "open", "assigned", "closed" (optional)
assignedTo   - Filter by agent ID (optional, use "unassigned" for no agent)
page         - Page number, default 1
pageSize     - Results per page, default 25, max 100
search       - Search visitor name or message content (optional)
sortBy       - Sort field: "createdAt", "lastMessageAt" (default: "lastMessageAt")
sortOrder    - "asc" or "desc" (default: "desc")
Response 200
{
  "data": [
    {
      "id": "conv_abc123",
      "status": "open",
      "visitorName": "John Doe",
      "visitorEmail": "[email protected]",
      "assignedAgentId": null,
      "assignedAgent": null,
      "lastMessage": {
        "content": "Hi, I need help with billing",
        "sentAt": "2024-01-15T14:30:00Z",
        "senderType": "visitor"
      },
      "messageCount": 3,
      "createdAt": "2024-01-15T14:28:00Z",
      "updatedAt": "2024-01-15T14:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 25,
    "totalCount": 142,
    "totalPages": 6
  }
}

Get Conversation

GET/conversations/{id}

Get full details of a single conversation including visitor metadata.

Auth: Workspace token (agent)

Response 200
{
  "id": "conv_abc123",
  "status": "assigned",
  "visitorName": "John Doe",
  "visitorEmail": "[email protected]",
  "visitorMetadata": {
    "browser": "Chrome 120",
    "os": "macOS",
    "page": "/pricing",
    "referrer": "https://google.com"
  },
  "assignedAgentId": "agt_xyz789",
  "assignedAgent": {
    "id": "agt_xyz789",
    "fullName": "Sarah Agent",
    "avatarUrl": null
  },
  "tags": ["billing", "urgent"],
  "messageCount": 12,
  "createdAt": "2024-01-15T14:28:00Z",
  "updatedAt": "2024-01-15T15:10:00Z",
  "closedAt": null
}

Update Conversation

PATCH/conversations/{id}

Update conversation status or assign to an agent.

Auth: Workspace token (agent)

Request Body
{
  "status": "closed",
  "assignedAgentId": "agt_xyz789"
}

Both fields are optional — send only what you want to update.

Response 200
{
  "id": "conv_abc123",
  "status": "closed",
  "assignedAgentId": "agt_xyz789",
  "updatedAt": "2024-01-15T15:12:00Z",
  "closedAt": "2024-01-15T15:12:00Z"
}
⚠️Closing a conversation sends a ConversationUpdated event via SignalR to all connected agents and the visitor. The visitor's widget will show a "conversation ended" state.

Get Conversation Messages

GET/conversations/{id}/messages

Get all messages in a conversation, ordered chronologically.

Auth: Workspace token (agent)

Query Parameters
page         - Page number, default 1
pageSize     - Results per page, default 50, max 200
before       - Cursor: get messages before this timestamp (ISO 8601)
Response 200
{
  "data": [
    {
      "id": "msg_001",
      "conversationId": "conv_abc123",
      "content": "Hi, I need help with billing",
      "senderType": "visitor",
      "senderName": "John Doe",
      "senderId": null,
      "isInternal": false,
      "createdAt": "2024-01-15T14:28:00Z"
    },
    {
      "id": "msg_002",
      "conversationId": "conv_abc123",
      "content": "Sure, I can help with that! What's your account email?",
      "senderType": "agent",
      "senderName": "Sarah Agent",
      "senderId": "agt_xyz789",
      "isInternal": false,
      "createdAt": "2024-01-15T14:29:00Z"
    },
    {
      "id": "msg_003",
      "conversationId": "conv_abc123",
      "content": "Check their last invoice — might be a duplicate charge",
      "senderType": "agent",
      "senderName": "Mike Lead",
      "senderId": "agt_def456",
      "isInternal": true,
      "createdAt": "2024-01-15T14:29:30Z"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 50,
    "totalCount": 3,
    "totalPages": 1
  }
}
💡Messages with isInternal: true are internal notes visible only to agents. They are never sent to the visitor via SignalR or the widget.

Status Values

  • open — New conversation, not yet picked up by an agent
  • assigned — An agent has been assigned (manually or via auto-assign on first reply)
  • closed — Conversation is resolved. Can be reopened by changing status back to "open"