Skip to main content

Support Conversation Controller

Controller: support.conversation.controller.js
Module: Conversation-v2
Purpose: Manages customer support chat sessions, token-based authentication for embedded widgets, and OTP verification

Overview

The Support Conversation controller handles customer-facing support chat functionality. It manages support sessions for website visitors, token generation for embedded chat widgets, OTP verification for secure sessions, and support configuration retrieval.

Methods

1. Get Support Conversation (getSupportConv)

Retrieves a support conversation by ID (admin/agent access).

Endpoint: GET /api/conversation-v2/support/conversation/:conv_id

Authentication: Required (JWT - team member)

Response:

{
"_id": "507f1f77bcf86cd799439011",
"account_id": "507f1f77bcf86cd799439012",
"contact_id": "507f1f77bcf86cd799439013",
"type": "support",
"status": "active",
"sessions": [
{
"session_id": "507f1f77bcf86cd799439014",
"device_id": "device_xyz123",
"ip": "192.168.1.100",
"started_at": "2025-10-08T10:30:00.000Z",
"last_activity": "2025-10-08T11:00:00.000Z"
}
],
"created_at": "2025-10-08T10:00:00.000Z"
}

MongoDB Operations:

CollectionOperationQueryPurpose
support_conversationsfindOne{ _id: conv_id }Get conversation details

Business Logic:

  • Returns full support conversation with session history
  • Used by agents to view customer context
  • Includes device and IP tracking for security

Use Cases:

  • Agent viewing customer conversation details
  • Admin reviewing support interactions
  • Debugging support session issues

2. Generate Token (generateToken)

Creates an authentication token for embedding chat widget on external websites.

Endpoint: POST /api/conversation-v2/support/token

Authentication: Required (JWT - admin)

Request Body:

{
"domain": "https://example.com",
"scopes": ["chat", "support"],
"expiry_time": 31536000000
}

Response:

{
"success": true,
"token": {
"_id": "507f1f77bcf86cd799439020",
"account_id": "507f1f77bcf86cd799439012",
"domain": "https://example.com",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"scopes": ["chat", "support"],
"expiry_time": 31536000000,
"created_by": "507f1f77bcf86cd799439013",
"created_at": "2025-10-08T10:30:00.000Z",
"status": "active"
}
}

MongoDB Operations:

CollectionOperationQueryPurpose
support_tokensinsertOneNew tokenCreate auth token

Business Logic:

  • Generates JWT token for public-facing chat widget
  • Token scoped to specific domain for security
  • Expiry time in milliseconds (default: 1 year)
  • Allows widget to authenticate without user credentials

Token Scopes:

  • chat - Basic chat functionality
  • support - Access to support features
  • file_upload - Allow file attachments
  • history - View chat history

Token Generation Flow:

graph TD
A[Admin Creates Token] --> B[Specify Domain]
B --> C[Set Scopes & Expiry]
C --> D[Generate JWT]
D --> E[Store in Database]
E --> F[Return Token String]
F --> G[Embed in Website]
G --> H[Widget Authenticates]

Security Considerations:

  • Tokens domain-locked to prevent misuse
  • Short expiry for sensitive scopes
  • Tokens can be revoked via removeToken

Use Cases:

  • Embedding support chat on company website
  • Mobile app support integration
  • Third-party platform chat widgets

3. Regenerate Token (reGenerateToken)

Regenerates an existing token (useful when token compromised).

Endpoint: POST /api/conversation-v2/support/token/regenerate

Authentication: Required (JWT - admin)

Request Body:

{
"id": "507f1f77bcf86cd799439020",
"domain": "https://example.com"
}

Response:

{
"success": true,
"token": {
"_id": "507f1f77bcf86cd799439020",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.NEW_TOKEN...",
"domain": "https://example.com",
"regenerated_at": "2025-10-08T10:30:00.000Z"
}
}

MongoDB Operations:

CollectionOperationQuery/UpdatePurpose
support_tokensfindOne{ _id: id, account_id }Get existing token
support_tokensupdateOne$set: { token }Update with new token

Business Logic:

  • Invalidates old token immediately
  • Generates new JWT with same settings
  • Preserves token ID, domain, and scopes
  • Requires re-deployment of widget with new token

When to Regenerate:

  • Token leaked or compromised
  • Security audit requirements
  • Rotating credentials periodically
  • Domain ownership change

Use Cases:

  • Security incident response
  • Token rotation policy
  • Domain transfer scenarios

4. Get Token (getToken)

Retrieves all active support tokens for the account.

Endpoint: GET /api/conversation-v2/support/token

Authentication: Required (JWT - admin)

Response:

{
"success": true,
"token": [
{
"_id": "507f1f77bcf86cd799439020",
"domain": "https://example.com",
"scopes": ["chat", "support"],
"status": "active",
"created_at": "2025-10-08T10:30:00.000Z",
"expiry_time": 31536000000,
"last_used": "2025-10-08T11:00:00.000Z"
},
{
"_id": "507f1f77bcf86cd799439021",
"domain": "https://app.example.com",
"scopes": ["chat"],
"status": "active",
"created_at": "2025-10-07T09:00:00.000Z"
}
]
}

MongoDB Operations:

CollectionOperationQueryPurpose
support_tokensfind{ account_id }List all tokens

Business Logic:

  • Returns all tokens for current account
  • Includes usage statistics (last_used)
  • Shows token status (active/expired)
  • Does not return actual token strings (security)

Use Cases:

  • Token management dashboard
  • Auditing widget deployments
  • Reviewing active integrations

5. Remove Token (removeToken)

Deletes a support token, invalidating all widgets using it.

Endpoint: DELETE /api/conversation-v2/support/token/:id

Authentication: Required (JWT - admin)

Response:

{
"success": true,
"message": "Token deleted"
}

MongoDB Operations:

CollectionOperationQueryPurpose
support_tokensdeleteOne{ _id: id, account_id }Remove token

Business Logic:

  • Immediately invalidates token
  • All widgets using this token stop working
  • Orphaned sessions remain accessible to agents
  • Irreversible action (must generate new token)

Impact:

graph TD
A[Admin Deletes Token] --> B[Token Removed from DB]
B --> C[Widget Auth Fails]
C --> D[Visitors See Error]
D --> E[Must Deploy New Token]

Use Cases:

  • Removing deprecated widget
  • Revoking compromised token
  • Shutting down external integration

6. Get Support Conversation (Public) (getSupportConversation)

Creates or retrieves a support session for website visitors (public endpoint).

Endpoint: POST /api/conversation-v2/support/session

Authentication: Support token (from widget)

Headers:

Authorization: Bearer <support_token>
X-Device-ID: device_xyz123

Request Body:

{
"email": "customer@example.com",
"name": "John Doe",
"phone": "+1234567890",
"auth_attr": {
"user_id": "external_user_123",
"custom_field": "value"
}
}

Response:

{
"success": true,
"session": {
"session_id": "507f1f77bcf86cd799439030",
"conversation_id": "507f1f77bcf86cd799439031",
"contact": {
"_id": "507f1f77bcf86cd799439032",
"name": "John Doe",
"email": "customer@example.com",
"phone": "+1234567890"
},
"status": "active",
"requires_verification": false,
"device_id": "device_xyz123",
"created_at": "2025-10-08T10:30:00.000Z"
}
}

MongoDB Operations:

CollectionOperationQueryPurpose
contactsfindOneAndUpdateUpsert by email/phoneGet or create contact
support_conversationsfindOneCheck existing sessionReuse session
support_conversationsinsertOneNew conversationCreate if needed
support_sessionsinsertOneNew sessionCreate session

Business Logic:

  • Contact matching by email or phone (creates if new)
  • Session tracking per device (device_id from header)
  • IP address logging for security
  • Returns existing session if recent (within 24 hours)
  • Custom attributes stored in auth_attr for context

Session Creation Flow:

graph TD
A[Visitor Opens Chat] --> B{Email/Phone Provided?}
B -->|Yes| C[Find/Create Contact]
B -->|No| D[Anonymous Session]
C --> E{Existing Session?}
E -->|Yes| F[Return Existing]
E -->|No| G[Create New Session]
D --> G
G --> H[Generate Session ID]
H --> I[Return to Widget]

Contact Matching Logic:

// Priority order:
1. Exact email match
2. Exact phone match
3. Create new contact

Use Cases:

  • Website visitor initiating chat
  • Mobile app user requesting support
  • Authenticated user continuing conversation

7. Get Support Config (getSupportConfig)

Retrieves public support widget configuration.

Endpoint: GET /api/conversation-v2/support/config

Authentication: Support token

Response:

{
"success": true,
"config": {
"widget_settings": {
"theme": "light",
"primary_color": "#007bff",
"position": "bottom-right",
"greeting_message": "Hi! How can we help you today?",
"offline_message": "We're offline. Leave a message!"
},
"features": {
"file_upload": true,
"emoji_picker": true,
"typing_indicators": true,
"read_receipts": true
},
"business_hours": {
"timezone": "America/New_York",
"schedule": {
"monday": { "start": "09:00", "end": "17:00" },
"tuesday": { "start": "09:00", "end": "17:00" }
}
},
"requires_email": false,
"requires_phone": false,
"otp_verification_enabled": false
}
}

MongoDB Operations:

CollectionOperationQueryPurpose
support_configsfindOne{ account_id }Get config

Business Logic:

  • Returns account-specific widget configuration
  • Used by widget to customize appearance and behavior
  • Determines required fields (email, phone)
  • Specifies enabled features

Configuration Categories:

  1. Widget Settings: Visual appearance
  2. Features: Functional capabilities
  3. Business Hours: Availability schedule
  4. Verification: Security requirements

Use Cases:

  • Widget initialization on website
  • Customizing chat appearance per brand
  • Enforcing data collection requirements

8. Send OTP (sendOTP)

Sends a one-time password for session verification.

Endpoint: POST /api/conversation-v2/support/otp/send

Authentication: Support token + session

Response:

{
"success": true,
"message": "OTP sent successfully"
}

MongoDB Operations:

CollectionOperationQuery/UpdatePurpose
support_sessionsupdateOneStore OTP + expirySave verification code

Business Logic:

  • Generates 6-digit OTP code
  • Valid for 10 minutes
  • Sent via email or SMS (based on contact info)
  • Rate limited to prevent abuse (max 3 per hour)

OTP Generation:

const otp = Math.floor(100000 + Math.random() * 900000); // 6 digits
const expiry = Date.now() + 10 * 60 * 1000; // 10 minutes

Delivery Methods:

graph TD
A[Generate OTP] --> B{Contact Has Email?}
B -->|Yes| C[Send Email]
B -->|No| D{Contact Has Phone?}
D -->|Yes| E[Send SMS]
D -->|No| F[Error: No Contact Method]
C --> G[Store in Session]
E --> G

Email Template:

Subject: Your verification code

Your verification code is: 123456

This code will expire in 10 minutes.

Use Cases:

  • Verifying customer identity
  • Secure support for sensitive issues
  • Preventing unauthorized access

9. Verify OTP (verifyOTP)

Validates the OTP code provided by the user.

Endpoint: POST /api/conversation-v2/support/otp/verify

Authentication: Support token + session

Request Body:

{
"code": "123456"
}

Response:

{
"success": true,
"message": "OTP is verified"
}

MongoDB Operations:

CollectionOperationQuery/UpdatePurpose
support_sessionsfindOneGet session with OTPValidate code
support_sessionsupdateOneMark as verifiedUpdate status

Business Logic:

  • Compares provided code with stored OTP
  • Checks expiry time (10 minute window)
  • Marks session as verified on success
  • Clears OTP after successful verification
  • Max 3 attempts before generating new OTP

Verification Flow:

graph TD
A[User Enters Code] --> B{Code Matches?}
B -->|Yes| C{Within Time Limit?}
B -->|No| D[Increment Attempts]
C -->|Yes| E[Mark Verified]
C -->|No| F[Error: Expired]
D --> G{Max Attempts?}
G -->|Yes| H[Error: Too Many Attempts]
G -->|No| I[Try Again]
E --> J[Grant Access]

Error Responses:

// Invalid code
{
"error": "Invalid OTP code",
"statusCode": 400
}

// Expired code
{
"error": "OTP has expired",
"statusCode": 400
}

// Too many attempts
{
"error": "Too many failed attempts. Request new OTP.",
"statusCode": 429
}

Use Cases:

  • Completing identity verification
  • Unlocking verified-only features
  • Account-specific support access

Data Models

Support Conversation Schema

{
_id: ObjectId;
account_id: ObjectId;
contact_id: ObjectId; // Linked contact
type: 'support';

// Session Tracking
sessions: Array<{
session_id: ObjectId;
device_id: string;
ip: string;
started_at: Date;
last_activity: Date;
verified: boolean;
}>;

// Authentication
auth_attr: object; // Custom attributes

// Status
status: 'active' | 'closed';

// Timestamps
created_at: Date;
updated_at: Date;
}

Support Token Schema

{
_id: ObjectId;
account_id: ObjectId;
user_id: ObjectId; // Creator

// Token Details
token: string; // JWT string
domain: string; // Allowed origin
scopes: string[]; // Permissions

// Lifecycle
expiry_time: number; // Milliseconds
status: 'active' | 'revoked';
last_used: Date;

// Timestamps
created_at: Date;
regenerated_at?: Date;
}

Support Session Schema

{
_id: ObjectId;
conversation_id: ObjectId;
device_id: string;
ip: string;

// OTP Verification
otp_code?: string;
otp_expiry?: number;
otp_attempts: number;
verified: boolean;

// Status
status: 'active' | 'inactive';

// Timestamps
created_at: Date;
last_activity: Date;
}

Security Considerations

Token Security

  1. Domain Whitelisting: Tokens only work on specified domains
  2. Token Rotation: Regular regeneration recommended
  3. Scope Limitation: Minimal permissions principle
  4. Revocation: Instant invalidation capability

Session Security

  1. Device Tracking: Device ID from browser fingerprint
  2. IP Logging: Fraud detection and security auditing
  3. Session Expiry: Automatic timeout after inactivity
  4. OTP Verification: Optional second factor

Rate Limiting

// OTP requests
- Max 3 OTP sends per hour per contact
- Max 3 verification attempts per OTP

// Session creation
- Max 10 sessions per IP per hour
- Max 5 concurrent sessions per device

Integration Points

Widget Integration

<!-- Embed support chat on website -->
<script>
window.supportConfig = {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
position: 'bottom-right',
};
</script>
<script src="https://cdn.example.com/support-widget.js"></script>

Mobile App Integration

// Initialize support session
const session = await fetch('/api/conversation-v2/support/session', {
method: 'POST',
headers: {
Authorization: `Bearer ${supportToken}`,
'X-Device-ID': deviceId,
},
body: JSON.stringify({
email: user.email,
name: user.name,
}),
});

Performance Considerations

Caching Strategy

// Support config cached for 5 minutes
GET /support/config
Cache-Control: public, max-age=300

// Token list not cached (security)
GET /support/token
Cache-Control: no-store

Database Indexing

// support_conversations
db.support_conversations.createIndex({ contact_id: 1, account_id: 1 });
db.support_conversations.createIndex({ 'sessions.device_id': 1 });

// support_tokens
db.support_tokens.createIndex({ account_id: 1, status: 1 });
db.support_tokens.createIndex({ domain: 1 });

// support_sessions
db.support_sessions.createIndex({ conversation_id: 1, device_id: 1 });

Error Handling

Status CodeErrorCause
400Invalid OTP codeWrong verification code
401Invalid support tokenToken expired or revoked
403Domain not whitelistedToken domain mismatch
429Too many OTP requestsRate limit exceeded

Testing Recommendations

describe('Support Conversation Controller', () => {
describe('generateToken', () => {
it('should create token with domain', async () => {});
it('should enforce domain whitelist', async () => {});
});

describe('getSupportConversation', () => {
it('should create new contact and session', async () => {});
it('should reuse existing session', async () => {});
it('should track device and IP', async () => {});
});

describe('OTP flow', () => {
it('should send OTP to email', async () => {});
it('should verify valid OTP', async () => {});
it('should reject expired OTP', async () => {});
it('should enforce rate limits', async () => {});
});
});

Last Updated: October 8, 2025
Documented By: AI Documentation System
Source: internal/api/v1/conversation-v2/controllers/support.conversation.controller.js

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM