A comprehensive package for managing Plivo voice calls with sticky agent routing, IVR support, and call management features
npm install plivo-voice-call-managerA comprehensive npm package for managing Plivo voice calls with advanced features like sticky agent routing, IVR support, out-of-office handling, and intelligent call routing.
- Sticky Agent Routing: Automatically routes calls to the last agent who called the customer
- Employee-Based Routing: Routes calls to assigned employees based on customer relationships
- IVR Support: Full support for Interactive Voice Response systems
- Out-of-Office Handling: Configurable out-of-office messages and behavior
- Call Recording: Automatic call recording with callback support
- Status Determination: Intelligent call status determination based on business logic
- Sequential & Simultaneous Dialing: Support for both routing modes
- Extensible: Adapter-based architecture for easy integration with any database/ORM
``bash`
npm install plivo-voice-call-manager
`javascript
const plivoManager = require('plivo-voice-call-manager');
// Define your database adapters
const adapters = {
findVoiceCall: async ({ sid }) => {
// Your database query to find a call by SID
return await VoiceCall.findOne({ where: { sid } });
},
createVoiceCall: async (callData) => {
// Your database query to create a call record
return await VoiceCall.create(callData);
},
updateVoiceCall: async (sid, updates) => {
// Your database query to update a call record
return await VoiceCall.update(updates, { where: { sid } });
},
getMerchantByDID: async (did) => {
// Your database query to get merchant by DID
return await VoiceCallDidMap.getVoiceCallDidMap(did);
},
findAvailableAgents: async ({ plivoNumber, status, limit, orderBy }) => {
// Your database query to find available agents
return await VoiceCallAgent.findAll({
where: { plivo_phone_number: plivoNumber, status },
order: orderBy,
limit
});
},
// ... other adapters
};
// Configure webhook handlers
const config = {
webhookBaseUrl: 'https://your-domain.com',
recordingCallbackUrl: 'https://your-domain.com/api/v1/webhook/plivo/recording-callback',
dialCallbackUrl: 'https://your-domain.com/api/v1/webhook/plivo/dial-callback',
onCallCompleted: async ({ call, direction }) => {
// Your automation logic
console.log(Call ${call.sid} completed (${direction}));Call ${call.sid} was missed
},
onMissedCall: async ({ call }) => {
// Your missed call handling
console.log();Call ${call.sid} received during OOO hours
},
onOutOfOffice: async ({ call }) => {
// Your out-of-office handling
console.log();
}
};
// Handle incoming call webhook
app.post('/webhook/plivo/incoming', async (req, res) => {
const response = await plivoManager.webhooks.handleIncomingCall(
req.body,
adapters,
config
);
res.status(response.statusCode).send(response.body);
});
// Handle hangup webhook
app.post('/webhook/plivo/hangup', async (req, res) => {
const response = await plivoManager.webhooks.handleHangup(
req.body,
adapters,
config
);
res.status(response.statusCode).send(response.body);
});
`
#### webhooks.handleHangup(event, adapters, config)
Handles Plivo hangup webhook events for both inbound and outbound calls.
#### webhooks.handleIncomingCall(event, adapters, config)
Handles incoming call webhooks with automatic agent routing.
#### webhooks.handleIVRIncomingCall(event, adapters, config)
Handles IVR-enabled incoming calls.
#### webhooks.handleIVRAction(event, adapters, config)
Handles IVR digit input actions.
#### webhooks.handleRecordingCallback(event, adapters)
Handles call recording completion callbacks.
#### webhooks.handleDialCallback(event, adapters)
Handles dial action callbacks (A-leg and B-leg management).
#### routing.routeAgents(options)
Intelligently routes agents based on priority:
1. Sticky agent (last agent who called customer)
2. Employee agent (assigned employee)
3. Available agents (from agent pool)
#### routing.findStickyAgent(options)
Finds the sticky agent for a customer.
#### routing.findEmployeeAgent(options)
Finds the employee agent for a customer.
#### routing.findAvailableAgents(options)
Finds available agents from the agent pool.
#### xml.createResponse()
Creates a new Plivo Response object.
#### xml.addRecording(response, callbackUrl, options)
Adds recording configuration to response.
#### xml.addSimultaneousDial(response, numbers, options)
Adds simultaneous dial configuration.
#### xml.addSequentialDial(response, numbers, options)
Adds sequential dial configuration.
#### xml.addIVRInput(response, actionUrl, message, options)
Adds IVR GetInput configuration.
#### xml.createOutOfOfficeResponse(message, options)
Creates an out-of-office response.
#### status.determineCallStatus(options)
Determines final call status based on business logic.
#### status.determineUserStatus(options)
Determines user/agent status.
#### status.determineCustomerStatus(options)
Determines customer status.
#### utils.normalizeNumber(number)
Normalizes phone numbers to E.164 format.
#### utils.parseWebhookEvent(event)
Parses webhook event body and query parameters.
#### utils.getParam(body, params, key)
Gets parameter from body or query params.
Your adapters should implement the following methods:
- findVoiceCall({ sid }) - Find call by SIDcreateVoiceCall(callData)
- - Create call recordupdateVoiceCall(sid, updates)
- - Update call recordupdateVoiceCallRecording(sid, recordingData)
- - Update recording infogetMerchantByDID(did)
- - Get merchant by DIDgetMerchantByPlivoNumber(plivoNumber)
- - Get merchant by Plivo numbergetIVRConfig(plivoNumber)
- - Get IVR configurationgetOutOfOfficeConfig(plivoNumber)
- - Get out-of-office configurationfindLastOutboundCall({ merchantId, customerNumber, hoursBack })
- - Find last outbound callfindCustomer({ merchantId, phoneNumber })
- - Find customerfindUserByEmployeeId(employeeId)
- - Find user by employee IDfindAvailableAgents({ plivoNumber, status, limit, orderBy })
- - Find available agentsfindAnsweredBlegs(callUuid)
- - Find answered B-legsprocessCustomers(customers)
- - Process/create customers
- webhookBaseUrl - Base URL for webhook callbacksrecordingCallbackUrl
- - URL for recording callbacksdialCallbackUrl
- - URL for dial callbacksonCallCompleted
- - Callback for completed callsonMissedCall
- - Callback for missed callsonOutOfOffice
- - Callback for out-of-office callssendIncomingCallEvent
- - Function to send incoming call socket events
`javascript`
const agents = await plivoManager.routing.routeAgents({
findLastOutboundCall: adapters.findLastOutboundCall,
findCustomer: adapters.findCustomer,
findUserByEmployeeId: adapters.findUserByEmployeeId,
findAvailableAgents: adapters.findAvailableAgents,
merchantId: 'merchant-123',
customerNumber: '+1234567890',
plivoNumber: '+1987654321',
limit: 8
});
`javascript`
const statusResult = plivoManager.status.determineCallStatus({
user_status: 'answered',
customer_status: 'completed',
plivo_status: 'completed',
hangup_cause_name: 'NORMAL_CLEARING',
is_out_of_office: false,
is_missed_call: false,
user_on_call_duration: 120,
total_call_duration: 120
});
`javascript``
const response = plivoManager.xml.createResponse();
plivoManager.xml.addRecording(response, 'https://example.com/recording-callback');
plivoManager.xml.addSimultaneousDial(response, ['+1234567890', '+0987654321'], {
timeout: '20',
callerId: '+1987654321',
callbackUrl: 'https://example.com/dial-callback'
});
const xml = response.toXML();
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
Satwik Loka