Conversation Integration
Namespace: /v1/conversation and /v1/conversation/live
Purpose: Internal team messaging and conversation management
Socket Events
Client → Server Events
| Event | Description | Authentication | Scope Required |
|---|---|---|---|
join | Join conversation namespace and set status active | Required | conversation |
disconnect | User disconnected (automatic) | N/A | N/A |
active_status | Update user presence status | Required | conversation |
add_conversation | Create new conversation | Required | conversation |
list_conversation | Get conversation list with filters | Required | conversation |
conversation_filter | Filter conversations by criteria | Required | conversation |
get_conversation_by_id | Fetch specific conversation | Required | conversation |
list_message | Get messages for conversation | Required | conversation |
list_message_by_id | Get messages centered on message ID | Required | conversation |
channel | Get channel counters and conversation list | Required | conversation |
typing | Broadcast typing indicator | Required | conversation |
read | Mark messages as read | Required | conversation |
snooze | Snooze conversation | Required | conversation |
archive | Archive conversation | Required | conversation |
open | Open/close conversation | Required | conversation |
show_on_top | Pin conversation to top | Required | conversation |
add_participant | Add users to conversation | Required | conversation |
message | Send new message | Required | conversation |
edit_conversation | Update conversation metadata | Required | conversation |
Server → Client Events
| Event | Description | Data Structure |
|---|---|---|
add_conversation | New conversation created | { _id, title, image, users, channel_id, is_open, unread_count, ... } |
active_status | User presence changed | { userID, conversation_active_status } |
list_conversation | Conversation list response | { conversation: [], messageList: {}, paging: {} } |
conversation_filter | Filtered conversation list | Same as list_conversation |
get_conversation_by_id | Single conversation data | { success, data: { conversation } } |
update_conversation | Conversation updated | { success, data: { conversation } } |
list_message | Message list response | { conversation: {}, messages: [], paging: {} } |
channel | Channel counters | { data: { counters }, conversation_list: {} } |
typing | User typing indicator | { userID, conversation_id, channel_id, is_typing } |
message | New message received | { UUID, data, attachments, sent_by, is_sender, ... } |
open | Conversation opened/closed | { conversationId, is_open, channel_id } |
archive | Conversation archived | { archive: true, conversationId, channel_id } |
snooze | Conversation snoozed | { snooze, snooze_till, conversationId, channel_id } |
show_on_top | Conversation pinned | { show_on_top, conversationId, channel_id } |
remove_user | User removed from conversation | { conversation_id } |
Database Models
- Conversation - Team conversations
- ConversationMessage - Messages in conversations
- ConversationChannel - Channel definitions (e.g., "Client Chat", "Internal")
- User - User data and socket IDs
Event Details
join
Purpose: Register user connection and set active status
Request:
socket.emit('join', {}, callback);
Response:
{ success: true, message: 'SUCCESS' }
Side Effects:
- Updates user's
conversation_socket_idsarray - Sets
conversation_active_statustoactive - Broadcasts
active_statusevent to all users in shared conversations
add_conversation
Purpose: Create new team conversation
Request:
socket.emit(
'add_conversation',
{
users: ['user_id_1', 'user_id_2'], // Array of participant IDs
title: 'Project Discussion', // Optional
channel_id: 'channel_id', // Required
origin: 'web', // Optional
},
callback,
);
Response:
{
success: true,
message: 'SUCCESS',
data: {
_id: '64abc...',
title: 'Project Discussion',
users: [...],
channel_id: 'channel_id',
unread_count: 0,
is_open: true,
...
}
}
Validation:
- At least 2 participants required
- Cannot create conversation with yourself only
- All users must exist in database
- Duplicate conversations are prevented (same participants + channel)
message
Purpose: Send new message in conversation
Request:
socket.emit(
'message',
{
conversation_id: '64abc...',
channel_id: 'channel_id',
UUID: 'unique-uuid-v4',
data: 'Hello team!',
attachments: [
{
type: 'image',
url: 'https://...',
name: 'screenshot.png',
},
],
mentions: ['user_id_1'], // Optional @mentions
},
callback,
);
Response:
{
success: true,
message: 'SUCCESS',
data: {
UUID: 'unique-uuid-v4',
conversation_id: '64abc...',
data: 'Hello team!',
sent_by: { _id, name, email, image },
is_sender: true,
createdAt: '2025-10-13T10:30:00.000Z',
...
}
}
Side Effects:
- Increments
unread_countfor all participants except sender - Updates
last_activityin conversation - Emits
messageevent to all active participant sockets - Sends FCM push notification to offline users
- Un-snoozes conversation if snoozed
typing
Purpose: Broadcast typing indicator to conversation participants
Request:
socket.emit(
'typing',
{
conversation_id: '64abc...',
channel_id: 'channel_id',
is_typing: true,
},
callback,
);
Response:
{ success: true, message: 'SUCCESS' }
Broadcast:
All active participants receive:
{
userID: 'sender_id',
conversation_id: '64abc...',
channel_id: 'channel_id',
is_typing: true
}
Note: Typically sent when user starts typing, and again with is_typing: false when stops.
read
Purpose: Mark all messages as read in conversation
Request:
socket.emit(
'read',
{
conversation_id: '64abc...',
channel_id: 'channel_id',
},
callback,
);
Response:
{ success: true, message: 'SUCCESS' }
Side Effects:
- Sets
unread_count[userID]to 0 - Adds userID to
read_byarray in all messages - No broadcast to other users (personal action)
snooze
Purpose: Temporarily hide conversation
Request:
socket.emit(
'snooze',
{
conversation_id: '64abc...',
channel_id: 'channel_id',
time: 60, // Minutes (0 = indefinite)
},
callback,
);
Response:
{
success: true,
message: 'SUCCESS',
data: { snooze: true }
}
Broadcast (to sender only):
{
snooze: true,
snooze_till: '2025-10-13T11:30:00.000Z',
conversationId: '64abc...',
channel_id: 'channel_id'
}
Behavior:
time: 0→ Snooze indefinitelytime: 60→ Snooze for 60 minutes- Snoozed conversations hidden from "OPEN" filter
- Shown in "SNOOZE" filter
- Auto-unsnooze when time expires
list_conversation
Purpose: Get paginated conversation list with optional filters
Request:
socket.emit(
'list_conversation',
{
channel_id: 'channel_id',
filter: 'OPEN', // 'OPEN', 'CLOSE', 'SNOOZE', 'UNREAD', 'PRIORITY'
sort: 'NEWEST', // 'NEWEST', 'OLDEST'
limit: 20,
next: '2025-10-13T10:00:00.000Z', // For pagination
},
callback,
);
Response:
{
conversation: [
{
_id: '64abc...',
title: 'Project Discussion',
image: ['https://...'],
users: [...],
unread_count: 3,
is_open: true,
show_on_top: false,
snooze: false,
last_activity: {...},
is_admin: true,
...
}
],
messageList: {
// First conversation's messages (if !next)
conversation: {...},
messages: [...],
paging: { limit: 20, sort: 'DESC', next: '...' }
},
paging: {
limit: 20,
next: '2025-10-13T09:00:00.000Z'
}
}
Filters:
- OPEN: Active, not snoozed
- CLOSE: Closed conversations
- SNOOZE: Snoozed conversations
- UNREAD: Has unread messages
- PRIORITY: Pinned (show_on_top)
channel
Purpose: Get all channel counters and optional conversation list
Request:
socket.emit(
'channel',
{
channel_id: 'channel_id', // Optional: also fetch conversations
filter: 'OPEN',
sort: 'NEWEST',
},
callback,
);
Response:
{
data: {
counters: {
'channel_id_1': {
_id: 'channel_id_1',
name: 'Client Chat',
open: 15,
unread: 3,
closed: 50,
priority: 2,
snoozed: 1
},
'prospect': { ... },
'you': { ... }, // All channels aggregated
'mentions': { ... } // Where user is @mentioned
}
},
conversation_list: { ... } // If channel_id provided
}
Client Example
import io from 'socket.io-client';
const socket = io('http://localhost:4000/v1/conversation', {
transports: ['websocket'],
query: { token: 'your_jwt_token' },
});
// Join
socket.emit('join', {}, response => {
console.log('Joined:', response);
});
// Listen for messages
socket.on('message', data => {
console.log('New message:', data);
// Update UI with new message
});
// Listen for typing
socket.on('typing', data => {
console.log(`${data.userID} is typing...`);
});
// Send message
socket.emit(
'message',
{
conversation_id: '64abc...',
channel_id: 'channel_id',
UUID: 'uuid-v4',
data: 'Hello!',
attachments: [],
},
response => {
console.log('Message sent:', response);
},
);
// Get conversations
socket.emit(
'list_conversation',
{
channel_id: 'channel_id',
filter: 'OPEN',
sort: 'NEWEST',
limit: 20,
},
response => {
console.log('Conversations:', response.conversation);
},
);