Skip to content

Customer Service

The Customer Service plugin provides 1v1 real-time audio/video customer service capabilities for Monibuca V6. It is suitable for online customer support, remote consultation, after-sales support, and similar scenarios.

  • 1v1 calls: Each session is limited to 2 participants (agent + customer), based on Room Service’s max_users: 2 constraint
  • No-login customer side: Customers can enter the call directly via link without account registration
  • Agent management: Five-state machine (Offline/Online/Ready/Ringing/Busy), supports check-in/check-out, ready/busy
  • Queue & dispatch system: Visitor queuing → FIFO auto-assignment → agent acceptance complete workflow
  • Incoming call ringing: Agent receives call notification with 30s countdown, supports audio/video accept or reject
  • Call transfer: Agent can transfer the call to another available agent without disconnecting the customer
  • Satisfaction rating: Customers can provide 1-5 star ratings after call ends, backend provides rating statistics
  • Audio mixing: Agent side can mix local audio files into the stream (e.g., background music, notification sounds)
  • Admin dashboard: Complete session management interface with session creation, user link/QR code generation

Set enable: true under the customer-service section in config.yaml (included in official binaries; depends on the built-in Room service).

graph TB
subgraph CS["CustomerService Plugin"]
SM["SessionManager<br/>Session management (DashMap + SQLite)"]
AP["AgentPool<br/>Agent pool (Round-Robin)"]
VQ["VisitorQueue<br/>Queue (FIFO)"]
RM["RingManager<br/>Ring management"]
HTTP["HTTP API<br/>/customer-service/*"]
Signal["WebSocket Signaling<br/>AcceptCall / EndCall / Transfer"]
end
subgraph RS["Room Service (Engine Built-in)"]
Room["Room Management<br/>max_users: 2"]
WS["WebSocket<br/>Signaling"]
end
subgraph Client["Clients"]
Agent["Agent Side<br/>Account login"]
Customer["Customer Side<br/>No login required"]
end
CS -->|"register_callbacks<br/>RoomType::CustomerService"| RS
HTTP --> SM
HTTP --> AP
HTTP --> VQ
Agent -->|"WebRTC (WHIP)"| Room
Customer -->|"WebRTC (WHIP)"| Room
Agent <-->|"WebSocket"| WS
Customer <-->|"WebSocket"| WS
Waiting → Active → Ended
StatusDescription
WaitingSession created, waiting for agent/customer to join
ActiveBoth parties have joined, call in progress
EndedCall has ended
Offline → Online → Ready → Ringing → Busy
↑ │
└──────────────────┘
StatusDescription
OfflineNot logged in / checked out
OnlineChecked in but not ready (break, wrap-up)
ReadyReady to accept calls (dispatch target)
RingingCall offered, awaiting accept/reject (default 30s timeout)
BusyCurrently in a call

State transitions:

  • Agent registers → Ready
  • Call dispatched → Ringing (30s timeout auto-returns to Ready, visitor re-queued)
  • Accept → Busy
  • Call ended → Ready
  • Reject → Ready (visitor re-queued)
  • Go offline → Offline
  • FIFO queue: Visitors queue in arrival order, max queue size configurable (default 200)
  • Polling dispatch: Backend checks queue every 500ms, uses Round-Robin algorithm to select ready agents
  • Two-phase dispatch: Dequeue → agent enters Ringing → accept to establish call
  • Instant dispatch: If an agent is available when visitor joins, queue is skipped
  • Timeout cleanup: Queue entries removed after timeout (default 10 minutes)

All endpoints are prefixed with /customer-service/.

MethodPathDescription
GET/sessionsGet session list
GET/sessions/{id}Get session details
POST/sessionsCreate new session
DELETE/sessions/{id}Close/delete session
POST/sessions/{id}/assignManually assign agent
POST/sessions/{id}/transferTransfer call to another agent
POST/sessions/{id}/rateSubmit satisfaction rating
GET/sessions/{id}/ratingGet session rating
MethodPathDescription
POST/agents/registerRegister agent (go online/ready)
POST/agents/{id}/offlineAgent go offline
POST/agents/{id}/availableSet agent to ready
POST/agents/{id}/acceptAccept incoming call
POST/agents/{id}/rejectReject incoming call
GET/agentsList all agents
GET/agents/availableList ready agents
GET/agents/statsAgent pool statistics
MethodPathDescription
POST/queue/joinVisitor join queue (instant dispatch if agent available)
POST/queue/leaveVisitor leave queue
GET/queue/statusQueue status snapshot
GET/queue/position/{visitor_id}Get queue position
MethodPathDescription
GET/statsCombined statistics (sessions + agents + queue + ratings)
GET/stats/ratingsRating statistics (total, average, distribution)
GET/stats/trend?days=7Daily session trend

Default base URL: http://localhost:8180

POST /customer-service/sessions
Content-Type: application/json

Request body:

{
"title": "After-sales inquiry",
"customer_id": "cust_001",
"customer_name": "John"
}
FieldTypeRequiredDescription
titlestringYesSession title
customer_idstringYesCustomer ID
customer_namestringNoCustomer display name
GET /customer-service/sessions

Response fields:

FieldTypeDescription
sessionsarraySession list
countintTotal sessions
GET /customer-service/sessions/{id}
ParamTypeRequiredDescription
idstringYesSession ID

Response (example):

{
"session_id": "cs_abc123",
"status": "waiting",
"created_at": "2026-05-07T19:05:00+08:00"
}
POST /customer-service/agents/register
Content-Type: application/json

Request body:

{
"agent_id": "agent_001",
"agent_name": "Agent Wang"
}
GET /customer-service/agents
GET /customer-service/agents/available
GET /customer-service/agents/stats
POST /customer-service/queue/join
Content-Type: application/json
FieldTypeRequiredDescription
visitor_idstringYesVisitor ID
visitor_namestringNoVisitor name
preferred_skillstringNoOptional skill group

Queue responses can be assigned (immediate dispatch) or queued.

GET /customer-service/queue/status
GET /customer-service/queue/position/{visitor_id}
ParamTypeRequiredDescription
visitor_idstringConditionalRequired for position lookup
POST /customer-service/sessions/{id}/transfer
Content-Type: application/json
FieldTypeRequiredDescription
target_agent_idstringYesTarget agent ID
POST /customer-service/sessions/{id}/rate
Content-Type: application/json

Request body:

{
"rating": 5,
"comment": "Great service"
}
FieldTypeRequiredDescription
ratingintYesScore from 1 to 5
commentstringNoText feedback
GET /customer-service/stats
GET /customer-service/stats/ratings
GET /customer-service/stats/trend?days=7
ParamTypeRequiredDescription
daysintNoTrend range days, default 7
HTTP StatusScenario
400Missing/invalid fields
404Session/agent not found
409State conflict (e.g. agent not Ready)
429Queue limit exceeded or too frequent requests

Authoritative field definitions and error codes are in the detailed section above.
Minimal example:

Terminal window
curl -X POST http://localhost:8180/customer-service/sessions \
-H "Content-Type: application/json" \
-d '{"title":"After-sales inquiry","customer_id":"cust_001"}'

Customer service calls use dedicated WebSocket signaling, which is forwarded to the plugin through the Room Service’s on_message callback.

ActionDirectionDescription
accept_callC→SAgent accepts the call
reject_callC→SAgent rejects the incoming call
end_callC→SEither party hangs up
transfer_callC→SAgent transfers to another agent
mute_userC→SMute a participant
unmute_userC→SUnmute a participant
incoming_callS→CIncoming call notification (with visitor_name, timeout_secs)
ring_timeoutS→CRing timeout notification
call_acceptedS→CNotify that the call has been answered
call_endedS→CNotify that the call has ended
call_transferredS→CNotify that the call has been transferred
transfer_failedS→CTransfer failed notification
agent_assignmentS→CAgent assignment notification
{
"type": "control",
"data": {
"type": "AcceptCall"
}
}
{
"type": "control",
"data": {
"type": "TransferCall",
"data": {
"target_agent_id": "agent_002"
}
}
}
customer_service:
max_sessions: 1000 # Maximum concurrent sessions
session_timeout_secs: 3600 # Session timeout (seconds), default 1 hour
max_queue_size: 200 # Maximum queue size
dispatch_interval_ms: 500 # Auto-dispatch polling interval (ms)
queue_timeout_secs: 600 # Queue timeout (seconds), default 10 minutes
accept_timeout_secs: 30 # Incoming call accept timeout (seconds), default 30s
auto_record: false # Enable call recording
recording_dir: "/tmp/cs-recordings" # Recording output directory

Clients join customer service calls via the standard Room WebSocket connection:

ws://host:port/room?type=customer_service

The room ID format is customer-service/{session_id}, using a prefix to distinguish different room types.


The customer service demo is built on Monibuca Web-SDK’s Web Components:

<!-- Room container -->
<mb-room id="room"></mb-room>
<!-- Local publisher -->
<mb-publisher id="publisher"></mb-publisher>
<!-- Remote subscriber -->
<mb-subscriber id="subscriber"></mb-subscriber>
const room = document.getElementById('room') as MbRoom;
const publisher = document.getElementById('publisher') as MbPublisher;
// Set up WebSocket connection
room.setAttribute('ws-url', 'ws://localhost:8180/room?type=customer_service');
room.setAttribute('room-id', 'customer-service/session_001');
// Start publishing
await publisher.startCapture({ audio: true, video: true });
await publisher.startPublish();

The agent side supports mixing local audio files into the stream, such as background music or waiting notification sounds:

const publisher = document.getElementById('publisher') as MbPublisher;
// Mix in a local audio file
publisher.mixAudio('bgm', '/audio/background-music.mp3', 0.3);
// Adjust mix volume (0.0 ~ 1.0)
publisher.setMixVolume('bgm', 0.5);
// Remove mix source
publisher.unmixAudio('bgm');

Mixing principle:

graph LR
Mic["Microphone<br/>MediaStream"] --> GainA["GainNode<br/>Mic volume"]
BGM["Audio File<br/>MediaElement"] --> GainB["GainNode<br/>Mix volume"]
GainA --> Dest["Destination<br/>Combined output"]
GainB --> Dest
Dest --> WHIP["WHIPClient<br/>WebRTC publish"]

Internally, the SDK uses the Web Audio API’s AudioContext to mix multiple audio sources (microphone + mix files) through GainNode into a single MediaStreamAudioDestinationNode, which is then output to the WebRTC stream.

It is recommended to use a state machine to manage the call flow:

type CallStage = 'waiting' | 'connecting' | 'connected' | 'ended';
// waiting → Waiting for the other party to join (display waiting UI, pulse animation)
// connecting → WebRTC connection being established
// connected → Call in progress (display video, timer, control bar)
// ended → Call ended (display call duration, satisfaction rating)

The customer service module provides a complete management interface in the Admin dashboard.

  • Auto-ready: Agent automatically registers as ready when entering the workstation
  • Real-time dashboard: Queue length, ready agents, busy agents shown in real-time
  • Auto-dispatch: System auto-assigns visitors, agent enters call without manual action
  • Manual entry: Fallback option to manually enter session ID
  • Call controls: Microphone/camera toggle, screen sharing
  • Call transfer: Click “Transfer” button during call, select an available agent
  • Text chat: Real-time text chat panel during call
  • Call statistics: Bitrate, packet loss, RTT displayed in real-time
  • Statistics cards: Total sessions, active calls, waiting for connection
  • Session list: Supports status filtering, search, batch operations, rating display
  • Create session: Enter title and description, auto-assign agent
  • Assign agent: Manually assign a session to a specific agent
  • Generate link: Generate dedicated entry links and QR codes for customers/agents
  • Average rating: Dashboard displays average satisfaction rating across all sessions
  • Rating distribution: 1-5 star distribution chart
  • Session list rating column: Each ended session shows customer rating stars

Customer service room data is collected through the Room Service’s reporting system and automatically filtered by the customer-service/ prefix for display in the Admin.


The complete customer service demo is located at web-sdk/packages/demo/customer-service/:

customer-service/
├── src/
│ ├── pages/
│ │ ├── Lobby/index.tsx # Entry: role selection
│ │ ├── CallRoom/index.tsx # Call: 1v1 video, controls, chat, rating
│ │ ├── AgentConsole/index.tsx # Agent workstation: queue monitor, incoming call
│ │ └── QueueWaiting/index.tsx # Customer queue waiting page
│ ├── services/api.ts # API wrapper
│ └── types/index.ts # Type definitions
├── package.json # port: 5476
└── vite.config.ts
Terminal window
cd web-sdk/packages/demo/customer-service
pnpm install
pnpm dev
# Visit http://localhost:5476

Customers enter the call directly via a parameterized link without logging in:

http://localhost:5476?session=cs_abc123&role=customer

Agents need to log in with credentials and enter the agent workstation:

http://localhost:5476?session=cs_abc123&role=agent

After login, the agent enters the AgentConsole page:

  • Click “Go Online” to register as ready
  • Real-time display of queue length and online agent count
  • Incoming call triggers a full-screen ring panel (30-second countdown)
  • Supports “Video Accept”, “Audio Accept”, “Reject” actions
  • After accepting, automatically navigates to the CallRoom

The demo automatically detects device type. On mobile devices:

  • Top-bottom split video layout
  • Fixed bottom control bar (with safe area adaptation)
  • Touch-optimized interactions