Embeddable API for controlling and manipulating the UI
Embeddable provides an API that allows developers to control the UI and flow of the application via the embedded CTI. It is based on the postMessage API.
Active call control
[ | 1.x]
Following APIs need to work with Web phone call event to get callId
.
Answer a ringing call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'answer',
callId: `call id`
}, '*');
// callId comes from web phone call event
// answer the current ringing call, call id default is current ringing call id.
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'answer',
}, '*');
Reject a ringing call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'reject',
callId: `call id`
}, '*');
To voicemail a ringing call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'toVoicemail',
callId: `call id`
}, '*');
Forward a ringing call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'forward',
callId: `call id`,
options: {
forwardNumber: 'forward_number'
}
}, '*');
Hangup a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'hangup',
callId: `call id`
}, '*');
// hangup current active call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'hangup',
}, '*');
Hold a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'hold',
callId: `call id`
}, '*');
Unhold a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'unhold',
callId: `call id`
}, '*');
Transfer a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'transfer',
callId: `call id`,
options: {
transferNumber: 'transfer_number'
}
}, '*');
Record a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'startRecord',
callId: `call id`
}, '*');
This will only work after the call has already started (Inbound call accepted/Oubound call connected)
Stop record a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'stopRecord',
callId: `call id`
}, '*');
Mute a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'mute',
callId: `call id`
}, '*');
Unmute a call
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-control-call',
callAction: 'unmute',
callId: `call id`
}, '*');
Embeddable widget
Show custom alert message
const requestId = Date.now().toString();
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-message-request',
requestId: requestId,
path: '/custom-alert-message',
alertMessage: 'Test info message',
alertLevel: 'info',
ttl: 5000 //5000ms => 5s
}, '*');
Note: alertLevel
can be info
, warning
or danger
.
const alertId = await RCAdapter.alertMessage({
message: 'Test info message',
level: 'info',
ttl: 5000 //5000ms => 5s, 0 for infinite
});
// Dismiss the alert message
RCAdapter.dismissMessage(alertId); // dismiss the alert message
// Dismiss all alert messages
RCAdapter.dismissMessage();
Alert with details
const alertId = await RCAdapter.alertMessage({
message: 'Can not log phone call',
ttl: 0,
level: 'danger',
details: [{
title: 'Description',
items: [{
id: '1',
type: 'text',
text: 'This is a longer more descriptive explanation of the problem that can expand over multiple lines.'
}],
}, {
title: 'Error from CRM',
items: [{
id: '1',
type: 'text',
text: 'OAU-1973 Contact not found'
}],
}, {
title: 'Actions',
items: [{
id: '1',
type: 'link',
text: 'Need help? Ask out community.',
href: 'https://community.ringcentral.com'
}, {
id: '2',
type: 'link', // when not href set, it will send a event with [button event](./sms-toolbar-button.md)
text: 'Resolve logging conflict',
}]
}]
})
Minimize/Hide/Remove the widget
Only for Adapter JS way:
Minimize:
RCAdapter.setMinimized(true);
// RCAdapter.setMinimized(false); // maximize
You can also disable
Minimize
feature by following here.
Hide:
RCAdapter.setClosed(true);
// RCAdapter.setClosed(false); // Show
Remove:
RCAdapter.dispose();
Popup the widget
Only for Adapter JS way and popup window feature enabled:
RCAdapter.popupWindow(); // popup the widget in a standalone window
Login and authorization
Log out user
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-logout'
}, '*');
Trigger Login button click
App will open login popup window after getting this command. Follow here to disable popup window, and receive oauth uri.
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-login'
}, '*');
This command only works when user is not logged in
Navigation
Open the dialer and start a call
Find the widget iframe and use postMessage
to send command and data:
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-call',
phoneNumber: `phone number`,
toCall: true,
}, '*');
This feature can be used for Click to Dial
. If you set toCall
to ture, it will start the call immediately.
If you are using Adapter JS way, just you can just call RCAdapter.clickToCall('phonenumber')
.
Here is tutorial to use RingCentral C2D library to quick implement Click to Dial
feature.
Navigate to arbitrary path
Navigate to path:
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-navigate-to',
path: '/messages', // '/meeting', '/dialer', '//history', '/settings'
}, '*');
Navigate back to previous path:
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-navigate-to',
path: 'goBack',
}, '*');
Go to the SMS tab
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-sms',
phoneNumber: `phone number`,
}, '*');
Go to SMS conversation for specific phone number
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-sms',
phoneNumber: `phone number`,
conversation: true, // will go to conversation page if conversation existed
}, '*');
Go to SMS page with prefilled text
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-sms',
phoneNumber: `phone number`,
text: `your text`
}]
}, '*');
If you are using Adapter JS way, just you can just call RCAdapter.clickToSMS('phonenumber', 'text')
.
Auto-populate SMS conversation text
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-auto-populate-conversation',
text: `your text`
}, '*');
This only works when user is already on the SMS conversation detail page. It will add the specified text into user's conversation input.
Go to SMS page with prefilled image/attachment
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-new-sms',
phoneNumber: `phone number`,
attachments: [{
name: 'test.txt',
content: 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', // base64 encoded data URI
}], // optional for sending MMS message with attachments
}]
}, '*');
This only works when user is already on the SMS conversation detail page. It will add the specified text into user's conversation input.
Schedule a meeting
Your applicaton needs to have the "Meeting" application scope for this to work.
// meeting info
const meetingBody = {
topic: "Embbnux Ji's Meeting",
meetingType: "Scheduled",
password: "",
schedule: {
startTime: 1583312400368,
durationInMinutes: 60,
timeZone: {
id: "1"
}
},
allowJoinBeforeHost: false,
startHostVideo: false,
startParticipantsVideo: false,
audioOptions: [
"Phone",
"ComputerAudio"
]
};
// send a request to schedule meeting
const requestId = Date.now().toString();
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-message-request',
requestId: requestId,
path: '/schedule-meeting',
body: meetingBody,
}, '*');
// listen response
window.addEventListener('message', function (e) {
var data = e.data;
if (data && data.type === 'rc-adapter-message-response') {
if (data.responseId === requestId) {
console.log(data.response);
}
}
});
Set presence
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-set-presence',
userStatus: 'Available', // Offline, Busy, Available
dndStatus: 'TakeAllCalls', // TakeAllCalls, DoNotAcceptAnyCalls, DoNotAcceptDepartmentCalls, TakeDepartmentCallsOnly
}, '*');
To get current presence status please refer this event.
Update ringtone settings
Set ringtone audio
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-update-ringtone',
name: 'CoolRingTone', // Ringtone name
uri: 'https://xxx.wav', // Ringtone URI, support http/https and base64 data URI
}, '*');
Set ringtone volume
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-update-ringtone',
volume: 0.5, // 0 - 1.0
}, '*');
If you are using Adapter JS way, just you can just call RCAdapter.updateRingtone({ name, uri, volume })
.