REST API Endpoints
The General Socket service exposes HTTP endpoints for triggering Socket.IO emissions from other services.
Base URL: http://localhost:4000
Prospect Endpoints
Base Path: /conversations/:channel/emit/
Emit Prospect Message
Endpoint: GET /conversations/:channel/emit/message/:messageID
Purpose: Broadcast prospect message to all conversation participants
Parameters:
channel- Channel identifier (typically'prospect')messageID- Communication document ID
Response:
{ success: true, message: 'SUCCESS' }
Controller: RestAPI/Controllers/Prospect.js :: emitAddMessage
Flow:
1. Fetch Communication by messageID
2. Populate sent_by (Contact or User based on type)
3. For each conversation_id in message:
- Find ConversationProspect
- Get all user socket IDs
- Emit 'prospect_message' to each socket
Example:
GET /conversations/prospect/emit/message/64abc123def456789
Socket Event Emitted:
io.to(socketID).emit('prospect_message', {
_id: '64msg...',
type: 'INCOMING', // or 'OUTGOING'
data: 'Message content',
sent_by: { _id, name, email, ... },
conversation_id: '64conv...',
is_sender: false, // true if sent_by matches current user
createdAt: '2025-10-13T10:30:00.000Z',
...
});
Emit Prospect Conversation
Endpoint: GET /conversations/:channel/emit/conversation/:convoID/:isNew
Purpose: Broadcast new/updated prospect conversation
Parameters:
channel- Channel identifierconvoID- ConversationProspect document IDisNew-'new'or'existing'
Response:
{ success: true, message: 'SUCCESS' }
Controller: RestAPI/Controllers/Prospect.js :: emitAddConversation
Flow:
1. Fetch ConversationProspect by convoID
2. Populate users, contact_id, last_activity
3. Generate title/image from contact if not set
4. For each user:
- Get user's socket IDs
- Emit 'prospect_add_conversation' with user-specific unread_count
Example:
GET /conversations/prospect/emit/conversation/64conv123/new
Socket Event Emitted:
io.to(socketID).emit('prospect_add_conversation', {
_id: '64conv...',
title: 'John Doe',
image: ['https://...'],
contact_id: { _id, name, email, phone, ... },
users: [...],
unread_count: 2, // User-specific
is_open: true,
isNew: true,
...
});
LeadFinder Endpoints
Base Path: /lead-finder/
Emit Custom Event
Endpoint: POST /lead-finder/:event
Purpose: Send custom event to specific lead scraper
Parameters:
event- Event name (e.g.,'scrape_task','health_check')
Request Body:
{
"socketId": "scraper-socket-id",
"payload": {
// Event-specific data
}
}
Response:
{ success: true, message: 'SUCCESS' }
Controller: RestAPI/Controllers/LeadFinder.js :: emit
Example:
POST /lead-finder/scrape_task
Content-Type: application/json
{
"socketId": "xyz123abc",
"payload": {
"task_id": "task_001",
"keyword": "plumber near me",
"location": "New York, NY",
"max_results": 50,
"timeout": 30000
}
}
Socket Event Emitted:
io.to('xyz123abc').emit('scrape_task', {
task_id: 'task_001',
keyword: 'plumber near me',
location: 'New York, NY',
max_results: 50,
timeout: 30000,
});
Common Emit Endpoints
Base Path: /emit/
Emit to Single User
Endpoint: POST /emit/:userId/:emitTo
Purpose: Send event to specific user (all their sockets)
Parameters:
userId- User document IDemitTo- Event name
Request Body:
{
// Event payload (any structure)
}
Response:
{ success: true, message: 'SUCCESS' }
Controller: RestAPI/Controllers/Common.js :: emit
Example:
POST /emit/64user123abc/notification
Content-Type: application/json
{
"title": "New Lead",
"message": "You have a new lead from John Doe",
"type": "lead_assigned",
"data": {
"lead_id": "64lead...",
"lead_name": "John Doe"
},
"timestamp": "2025-10-13T10:30:00.000Z"
}
Socket Event Emitted:
// To all user's sockets in /v1/shared namespace
io.to(socketID).emit('notification', {
title: 'New Lead',
message: 'You have a new lead from John Doe',
type: 'lead_assigned',
data: { ... },
timestamp: '2025-10-13T10:30:00.000Z'
});
Emit to Multiple Users
Endpoint: POST /emit/:emitTo
Purpose: Broadcast event to multiple users
Parameters:
emitTo- Event name
Request Body:
{
"userIds": ["64user1...", "64user2...", "64user3..."], // Array or single string
"data": {
// Event payload
}
}
Response:
{ success: true, message: 'SUCCESS' }
Controller: RestAPI/Controllers/Common.js :: emitMultiple
Example:
POST /emit/system_announcement
Content-Type: application/json
{
"userIds": ["64user1...", "64user2...", "64user3..."],
"data": {
"title": "Scheduled Maintenance",
"message": "System will be down Monday 2AM-4AM EST",
"priority": "high",
"action_url": "/maintenance-info"
}
}
Socket Event Emitted:
// To all sockets of all specified users
io.to(socketID).emit('system_announcement', {
title: 'Scheduled Maintenance',
message: 'System will be down Monday 2AM-4AM EST',
priority: 'high',
action_url: '/maintenance-info',
});
Error Handling
Error Response Format
{
success: false,
errno: 400, // HTTP status code
message: 'Error message'
}
Common Error Codes
| Code | Error | Cause |
|---|---|---|
| 400 | VALIDATION_ERROR | Missing required parameters |
| 404 | NOT_FOUND | Message/Conversation not found |
| 500 | `INTERNAL_SERVER_ERROR | Database or socket emission error |
Error Handling Middleware
router.use((error, req, res, next) => {
console.log('error--------------', error);
const status = error.statusCode || 400;
const message = error.message;
res.status(status).json({
success: false,
errno: status,
message: message,
});
});
Rate Limiting
Recommended: Implement rate limiting on REST API endpoints
Example with express-rate-limit:
const rateLimit = require('express-rate-limit');
const emitLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 100, // 100 requests per minute
message: { success: false, message: 'Too many emit requests' },
});
router.post('/emit/:userId/:emitTo', emitLimiter, commonController.emit);
router.post('/emit/:emitTo', emitLimiter, commonController.emitMultiple);
Authentication
Note: REST API endpoints currently have no authentication.
Recommendation for Production:
- Add API key authentication
- Verify requests from trusted services only
- Implement IP whitelisting
- Use internal network isolation
Example with API Key:
const apiKeyAuth = (req, res, next) => {
const apiKey = req.headers['x-api-key'];
if (apiKey !== process.env.INTERNAL_API_KEY) {
return res.status(401).json({
success: false,
message: 'Unauthorized',
});
}
next();
};
router.post('/emit/:userId/:emitTo', apiKeyAuth, commonController.emit);
Testing REST API
Using cURL
# Emit to single user
curl -X POST http://localhost:4000/emit/64user123/notification \
-H "Content-Type: application/json" \
-d '{
"title": "Test Notification",
"message": "This is a test"
}'
# Emit to multiple users
curl -X POST http://localhost:4000/emit/broadcast \
-H "Content-Type: application/json" \
-d '{
"userIds": ["64user1", "64user2"],
"data": {
"message": "System update"
}
}'
# Emit prospect message
curl -X GET http://localhost:4000/conversations/prospect/emit/message/64msg123
# Emit to scraper
curl -X POST http://localhost:4000/lead-finder/scrape_task \
-H "Content-Type: application/json" \
-d '{
"socketId": "scraper-xyz",
"payload": {
"task_id": "001",
"keyword": "test"
}
}'
Using Postman
- Create collection "General Socket API"
- Add requests for each endpoint
- Set
Content-Type: application/jsonheader - Test with actual user IDs and message IDs from database
Integration Example
From Internal API
// internal/api/v1/controllers/lead.controller.js
const axios = require('axios');
async function assignLead(leadId, userId) {
// Assign lead in database
await Lead.updateOne({ _id: leadId }, { assigned_to: userId });
// Notify user via socket
await axios.post(`${process.env.GENERAL_SOCKET_URL}/emit/${userId}/notification`, {
title: 'New Lead Assigned',
message: 'A new lead has been assigned to you',
type: 'lead_assigned',
data: {
lead_id: leadId,
timestamp: new Date().toISOString(),
},
});
return { success: true };
}
From External API (Webhook Handler)
// external/Integrations/Twilio/webhook.js
async function handleIncomingSMS(req, res) {
const { From, Body, To } = req.body;
// Create Communication record
const message = await Communication.create({
type: 'INCOMING',
data: Body,
from_number: From,
to_number: To,
conversation_id: [conversationId],
...
});
// Broadcast to all users in conversation
await axios.get(
`${process.env.GENERAL_SOCKET_URL}/conversations/prospect/emit/message/${message._id}`
);
res.status(200).send('OK');
}