API Spotlight: Presence

At a busy call center, it would be useful for a call operator to know the availability of a call agent before forwarding an incoming call to the agent. This would help a call operator to avoid forwarding an incoming call from a customer to an agent who is not available to pick up the call at that moment.

RingCentral cloud communication services include the capability to detect and change any user presence statuses. The presence statuses include the dynamic information of a user as explained below:

User status: This is the user-defined status for a user to set his/her availability such as available, busy or being offline. E.g. when a call agent goes for lunch, he can set his availability as Busy so a call operator would know that he is not available to take any call while he is at lunch. User status can be set together with a free text message to let other users know more about the status. E.g. a user can set his status as Busy and leaves the message as “In a meeting till 3:30pm”.

Presence status: this is the aggregated presence status, which is calculated by the system from several sources to notify the status of an extension as Available, Busy or Offline.

Telephony status: this is the state of the telephone line as it is idle (NoCall), or ringing (Ringing), or was put on hold (OnHold), or connected (CallConnected), or parked (ParkedCall). E.g. when there is an incoming call to an extension, the telephony state will change from NoCall to Ringing. And if the user picks up the call, the state will change again from Ringing to CallConnected.

Do not Disturb status: this is a special user status, which can be set to notify a user’s willingness to take any call or not. E.g. when a user is at an important meeting that he should not be disturbed by any phone calls, he can set this status to DoNotAcceptAnyCalls so the call operator would not forward any incoming call to this agent.

User statuses can be changed from the RingCentral soft-phone or mobile phone app.

Under the same account, other users’ presence statuses can be viewed from the HUD (Heads Up Display) view in the RingCentral soft-phone or mobile phone app.

Alternatively, user presence status can be accessed programmatically using the Presence API. We can use the API to read users’ presence statuses and display the statuses on a dashboard for call monitoring and handling purposes. Or we can build some logic to automate the call forwarding process.

How can I access RingCentral user presence statuses programmatically?

There are two access levels to read user presence statuses:

1. The Company Presence API allows users with the admin role to access presence statuses of all users under the same account. To read the company presence, send an HTTP GET request to the endpoint below: (Try it yourself)

https://platform.devtest.ringcentral.com/restapi/v1.0/account/{accountId}/presence

2. The User Presence API lets a user read his/her own presence status. To read a user presence statuses, make an HTTP GET request to the endpoint below: (Try it yourself)

https://platform.devtest.ringcentral.com/restapi/v1.0/account/{accountId}/extension/{extensionId}/presence

We can specify a couple query parameters to the API call:

“detailedTelephonyState”: specify this flag to true to retrieve detailed presence information including active calls’ information if there is an active call such as the direction of the call, the phone number or the name of a caller etc. See API reference for more details

“sipData” specify this flag to true to retrieve SIP data such as the recipient data, sender data etc. See API reference for more details.

User defined statuses and configuration can be updated programmatically as well. To change a user’s presence statuses, make an HTTP PUT request to the endpoint below, together with any parameters that need to be updated:

https://platform.devtest.ringcentral.com/restapi/v1.0/account/{accountId}/extension/{extensionId}/presence
{
"userStatus": "Busy",
"dndStatus": "DoNotAcceptAnyCalls",
"message": "In a meeting till 3:30pm",
"allowSeeMyPresence": true,
"ringOnMonitoredCall": true,
"pickUpCallsOnHold": true
}

If we do not want others users to see the statuses of a particular user, we can set the value of the allowSeeMyPresence for that user, to false.

User presence statuses are changing dynamically, and the Presence API just allows us to read the presence statuses at the moment the request is processed. Therefore, in order to monitor the statuses continuously, we will need to use the push notification API and set the notification event type filter for presence status changes, so that we will get the updated statuses every time there is a change.

What information can I get from the Presence API?

The Company Presence API response is a JSON object which contains an array of records. Each record item in the array contains presence statuses and configurations of a user (extension) as listed below:

“extension”: Contains the internal extension id and the user’s extension number. If we want to detect the name and other information of this user, we can use the internal extension id to define the end point of the Extension Info API to read the user’s information.

“presenceStatus”: See explanation on the first section. Click here for more details.

“telephonyStatus”: See explanation on the first section. Click here for more details.

“dndStatus”: See explanation on the first section. Click here for more details.

“allowSeeMyPresence”: If ‘True’ enables other users to see the extension presence status.

“ringOnMonitoredCall”: If ‘True’ enables to ring extension phone, if any user monitored by this extension is ringing.

“pickUpCallsOnHold”: If ‘True’ enables the extension user to pick up a monitored line.

Now, let’s use one of our favorite SDKs, the JavaScript SDK to make API calls to RingCentral platform.

Assumed that we already had an app created under our RingCentral developer account and we ‘ve got the app credentials in place (if not here is the 3 steps to create one). Our app’s platform type is a “Server-only (No UI)” and it must have the ReadPresense and the EditPresence permissions so we can read and update presence statuses.

In this demo project, we read all users presence statuses of a company (an account), parse the statuses of each user and display the status icons to a Web app dashboard. We also subscribe for the push notifications of Company Presence event type so we can receive updated user statuses to display on the monitor dashboard. Get project source code from Github: Node.JS

Let’s first implement the backend engine, where we import the RingCentral SDK and other dependencies, then get the platform instant so we can use it to call RingCentral APIs.

var RC = require('ringcentral')
var fs = require('fs')
require('dotenv').load()
var rcsdk = null
if (process.env.PROD == "production"){
rcsdk = new RC({
server:RC.server.production,
appKey: process.env.CLIENT_ID_PROD,
appSecret:process.env.CLIENT_SECRET_PROD
})
}else{
rcsdk = new RC({
server:RC.server.sandbox,
appKey: process.env.CLIENT_ID_SB,
appSecret:process.env.CLIENT_SECRET_SB
})
}
var platform = rcsdk.platform()

Then we implement an engine to login RingCentral platform and read presence statuses.

var hasUpdate = false
var extensions = []
var engine = module.exports = {
login: function(req, res){
var un = ""
var pwd = ""
if (process.env.PROD == "production"){
un= process.env.USERNAME_PROD,
pwd= process.env.PASSWORD_PROD
}else{
un= process.env.USERNAME_SB,
pwd= process.env.PASSWORD_SB
}
platform.login({
username:un,
password:pwd
})
.then(function(resp){
res.render('index')
})
.catch(function(e){
throw e
})
},
readPresence: function(req, res){
var endpoint = ""
if (req.query.accessLevel == "account")
endpoint = '/account/~/presence'
else
endpoint = '/account/~/extension/~/presence'

platform.get(endpoint, req.body)
.then(function(resp){
var json = resp.json()
if (json.records != undefined){
if (process.env.PRINT_LOG == "yes")
for (var record of json.records)
console.log("RESULT: " + JSON.stringify(record))
extensions = json.records
}else{
extensions = []
extensions.push(json)
}
res.send(JSON.stringify(extensions))
})
.catch(function(e){
var json = {
status: "FAILED"
}
res.send(json)
console.log("catch exception")
})
},
getUpdate: function(req, res){
if (hasUpdate){
hasUpdate = false
res.send(JSON.stringify(extensions))
}else {
res.send('[]')
}
}
}

We also implement functions to subscribe for push notifications of Company Presence events. When updated presence statuses arrive, we just update the extension array and set the hasUpdate flag to true. This will help us to avoid updating our dashboard when there is no change in the presence statuses.

var subcription = rcsdk.createSubscription()
function subscribeForNotification(){
var eventFilter['/restapi/v1.0/account/~/presence?detailedTelephonyState=true']
subcription.setEventFilters(eventFilter)
.register()
.then(function(resp){
console.log('ready to get account presense')
})
.catch(function(e){
throw e
})
}

subcription.on(subcription.events.notification, function(msg){
for (var i=0; i<extensions.length; i++){
var ext = extensions[i]
if (process.env.PRINT_LOG == "yes")
console.log("NOTIFICATION: " + JSON.stringify(msg.body))
if (ext.extension.id == msg.body.extensionId){
extensions[i].telephonyStatus = msg.body.telephonyStatus
extensions[i].presenceStatus = msg.body.presenceStatus
extensions[i].userStatus = msg.body.userStatus
extensions[i].dndStatus = msg.body.dndStatus
extensions[i].activeCalls = msg.body.activeCalls
extensions[i].message = msg.body.message
hasUpdate = true
break
}
}
})

For the frontend, we use JavaScript and the jQuery library to handle sending request to our server and to display the user statuses on the dashboard dynamically. The best way to build a great UI for this type of application is to use e.g. ReactJS or other frameworks that can dynamically update content from a server. However, to keep things simple for this demo, we just use a timer to poll our server for updated user statuses if they are available.

var timer = null
var pEngine = null
function readPresence(){
var url = "readpresence?accessLevel=" + $('#accessLevel').val()
var data = {}
data['detailedTelephonyState'] = $('#detailedTelephonyState').is(':checked')
data['sipData'] = $('#sipData').is(':checked')
var posting = $.post(url, data)
posting.done(function(response) {
var extensions = JSON.parse(response)
$("#results").empty()
pEngine = new PresenceData(extensions)
pEngine.displayPresence()
});
posting.fail(function(response){
alert(response.statusText);
});
}
function setUpdateTimer(){
if (timer == null){
$("#setTimer").text("Stop Auto Update")
timer = setInterval(function () {
updateData()
}, $("#timeInterval").val() * 1000);
}else{
$("#setTimer").text("Start Auto Update")
clearInterval(timer)
timer = null
}
}
function updateData(){
var posting = $.get("getupdate")
posting.done(function(response) {
var extensions = JSON.parse(response)
if (extensions.length > 0){
$("#results").empty()
pEngine = new PresenceData(extensions)
pEngine.displayPresence()
}
});
posting.fail(function(response){
alert(response.statusText);
});
}

This much for a demo for now. You can process and display user presence statuses the way you want and feel free to further develop this app to make it useful for your business.

Learn more about our Developer Program here: https://developer.ringcentral.com/