RingCX in Embeddable
Beta
RingCX support is part of the Embeddable 3.1.x beta.
RingCX is RingCentral's contact center product. With RingCX enabled, agents handle RingCX calls in Embeddable next to their RingEX (RingCentral phone) calls.
RingCX calls use the same events, commands, and registerThirdPartyService API as RingEX calls. You do not need a second protocol. To tell the two apart, check call.source: it is 'ringcx' for a RingCX call.
Quick start
1. Enable RingCX
Add enableRingCX=1 to the adapter.js or app.html URL. It is off by default and cannot be changed at runtime.
<script>
(function() {
var rcs = document.createElement("script");
rcs.src = "https://apps.ringcentral.com/integration/ringcentral-embeddable/3.1.x/adapter.js?clientId=YOUR_RINGCENTRAL_CLIENT_ID&enableRingCX=1";
var rcs0 = document.getElementsByTagName("script")[0];
rcs0.parentNode.insertBefore(rcs, rcs0);
})();
</script>
The Agent tab appears when the signed-in RingCentral user also has a RingCX account. RingCX reuses the RingCentral login, so there is no second login and no extra app scope. rc-login-status-notify reports features.ringCX, so your page can tell whether the user has RingCX.
Optional parameters:
| Parameter | Default | Description |
|---|---|---|
enableAgentScript |
off | Show RingCX agent scripts in the side panel during calls. Use it with enableSideWidget=1. |
2. Tell RingCX calls apart
In every call event and logger request, read call.source:
'ringcx': a RingCX call. RingCX-only fields are undercall.ringcx.'ringcentral', or nosource: a RingEX call.
Your existing callLoggerPath, contactMatchPath, and callLogEntityMatcherPath registrations apply to RingCX calls with no other change.
3. Handle RingCX call logging
The simplest path: accept triggerType: 'callDisposition' in your callLoggerPath handler. The widget sends it after the agent submits a disposition, and no log form is shown.
window.addEventListener('message', function (e) {
var data = e.data;
if (!data || data.type !== 'rc-post-message-request' || data.path !== '/callLogger') {
return;
}
var body = data.body;
if (body.call.source === 'ringcx' && body.triggerType === 'callDisposition') {
// body.call.ringcx.disposition: the disposition the agent picked
// body.call.ringcx.notes: the disposition notes
// body.redirect: true. Open the CRM record only if your own auto-log setting says so.
saveCallToCrm(body.call); // your code
}
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-post-message-response',
responseId: data.requestId,
response: { data: 'ok' },
}, '*');
});
To show your own log form on the agent's wrap-up page instead, see Call logging. That is the recommended setup.
4. Optional: open leads in your app
Register leadViewerPath to add View lead to the Lead tab. See Lead tab.
Concepts
| Term | Meaning |
|---|---|
| Agent tab | The widget tab for RingCX: agent state, calls, leads, and RingCX call history. |
| Agent session | The agent's RingCX login for this widget. Calls and commands need a session in the ready status. |
| Agent state | The agent's RingCX availability, such as AVAILABLE, ENGAGED, or ON-BREAK. An aux state is a named sub-state of a state, such as a break reason. |
| Integrated softphone | RingCX audio in the browser. It runs on the WebPhone: RingCX places a web phone call leg that carries the audio. That leg is not reported as a separate call. |
| Disposition | The outcome the agent records after a RingCX call, such as "Sale" or "No answer", plus optional notes. It is saved to RingCX. Until it is submitted, the agent is in Pending Disposition. |
| Wrap-up page | The page in the Agent tab's side panel where the agent submits the disposition and, optionally, your call log form. |
| Lead | A contact that a RingCX campaign assigns to the agent to call. |
| Dial group | The RingCX setting that decides how the agent dials leads. In a preview dial group, the agent picks a lead and dials it. In a progressive dial group, the widget dials leads one by one. |
Call lifecycle
- Start the session. The session does not start on first load. The agent starts it from the Agent tab, or your page calls
RCAdapter.startRingCXAgentSession(). Wait forrc-ringcx-agent-session-notifywithstatus: 'ready'. After a session has reachedready, it is restored automatically when the widget reloads, until the agent ends it. A user who is not a RingCX agent gets an error here. - Go available. The agent sets the state to
AVAILABLE, from the Agent tab or withrc-adapter-ringcx-set-agent-state. - Call. An inbound call rings (
rc-call-ring-notify), or the agent dials a number or a lead. The call connects (rc-call-start-notify) and later ends (rc-call-end-notify). - Wrap up. The agent submits the disposition, and your log form if there is one, on the wrap-up page (
rc-ringcx-call-disposed-notify). See Call logging. - Repeat. After a lead call, the widget goes back to the Leads tab.
rc-call-end-notify usually comes before the disposition. If the agent submits the disposition while the call is still connected, it comes after rc-ringcx-call-disposed-notify.
Call ids and times
call.idandcall.sessionIdare the same stable id: the RingCX calluii(RingCX's unique call id). A live call and its later history row have the same id. Use it withcallLogEntityMatcherPath.
Time formats differ
- Call events (
rc-call-*-notify,rc-ringcx-*-notify):startTimeis an ISO-8601 string. rc-active-call-notify:startTimeis epoch milliseconds, as for RingEX calls.callLoggerPathrequests:startTimeis epoch milliseconds, as for RingEX calls.
Events
Call events
RingCX calls use the existing call events, with call.source: 'ringcx'. The table lists only what is specific to RingCX calls; follow each link for the full event and payload.
| Event | When |
|---|---|
rc-call-ring-notify |
An inbound RingCX call is ringing. An auto-answered inbound call still sends it, right before rc-call-start-notify. |
rc-call-start-notify |
The RingCX call is connected. |
rc-call-end-notify |
The RingCX call ended. See Call lifecycle for its order with the disposition. |
rc-active-call-notify |
Sent on ring (inbound only), connect, and end, in the RingEX active call shape. See below. |
rc-call-drop-voicemail-notify |
The status of a voicemail drop on the call changed. call.voicemailDropStatus is set. |
rc-webphone-connection-status-notify |
The integrated softphone's connection status. It runs on the WebPhone, so there is no separate RingCX event. |
For rc-active-call-notify, call.telephonyStatus is Ringing, CallConnected, or NoCall (with terminationType: 'final'), and call.startTime is epoch milliseconds.
RingCX-only events
| Event | When |
|---|---|
rc-ringcx-agent-session-notify |
The session status, agent, or session configuration changed. |
rc-ringcx-agent-state-notify |
The agent state changed, while the session is ready. |
rc-ringcx-call-disposed-notify |
The agent submitted a disposition. |
rc-ringcx-lead-notify |
Leads were loaded, passed, dialed, or updated. |
rc-ringcx-progressive-dial-notify |
The progressive dialer started, stopped, moved to another step, or refused to start. |
rc-ringcx-agent-session-notify
{
type: 'rc-ringcx-agent-session-notify',
status: 'ready', // idle | loading | authenticating | chooseAccount | sessionConfig | ready | error
agent: { ... }, // optional
session: { ... }, // optional
permissions: { ... }, // optional, e.g. permissions.progressiveEnabled
}
chooseAccount and sessionConfig mean the agent must pick a RingCX account or configure the session in the Agent tab.
rc-ringcx-agent-state-notify
{
type: 'rc-ringcx-agent-state-notify',
state: 'AVAILABLE', // RingCX agent state, e.g. AVAILABLE, ENGAGED, ON-BREAK
auxState: '...',
pendingDisposition: false, // true while a disposition is still to be submitted
}
rc-ringcx-call-disposed-notify
{ type, call }, sent after the agent submits a disposition. call.ringcx.disposition and call.ringcx.notes are set, plus call.aiNote when the disposition form has a call summary. Calls without a disposition step do not send it.
rc-ringcx-lead-notify
{
type: 'rc-ringcx-lead-notify',
action: 'loaded', // loaded | passed | dialed | updated
leads: [ ... ], // optional
lead: { ... }, // optional
destination: '...', // optional
}
dialedis sent once the dial request is sent.updatedis sent once the agent saved an edit to the lead, with the saved fields onlead.
Each lead has this shape:
{ leadId, externId, campaignId, firstName, lastName, destination, raw }
raw is the original RingCX lead. A lead dialed by the progressive dialer has no destination, because the server picks the number.
rc-ringcx-progressive-dial-notify
{
type: 'rc-ringcx-progressive-dial-notify',
running: true,
phase: 'countdown', // idle | connecting | fetching | countdown | dialing | waiting | noLeads
nextDialAt: 1731300000000, // epoch ms of the next dial (countdown) or lead fetch (noLeads)
lead: { ... }, // optional: the lead the countdown dials, in the rc-ringcx-lead-notify shape
reason: null, // set when the dialer stopped or did not start
}
It is not sent for every countdown second. reason is one of stopped, notProgressive, busy, notAvailable, offhookFailed, offhookEnded, manualOutdial, inboundCall, agentState, dialGroupChanged, dialFailed, or logout. offhookFailed and offhookEnded mean the agent's line could not be connected, or was disconnected. See Progressive dialing.
Commands
Each command has an RCAdapter helper. rc-adapter-new-call and rc-adapter-control-call are the existing commands; the table lists only what is specific to RingCX calls.
| Command | RCAdapter helper |
Payload | Effect |
|---|---|---|---|
rc-adapter-ringcx-start-agent-session |
startRingCXAgentSession() |
{} |
Starts the agent session. |
rc-adapter-ringcx-end-agent-session |
endRingCXAgentSession() |
{} |
Ends the session. Refused while a call or pending disposition is active. |
rc-adapter-ringcx-set-agent-state |
setRingCXAgentState(state, auxState?) |
{ state, auxState? } |
Sets the agent state. See below. |
rc-adapter-new-call |
clickToCall(number, { callWith: 'ringcx', callerId }) |
{ phoneNumber, callWith: 'ringcx', callerId? } |
Places a RingCX call right away; toCall is not needed. callerId becomes the agent's manual dial caller ID. |
rc-adapter-control-call |
controlCall(action, id, { source: 'ringcx' }) |
{ callAction, callId, source: 'ringcx', options? } |
Controls the current RingCX call. See below. |
rc-adapter-ringcx-dial-lead |
dialRingCXLead(lead, destination) |
{ lead, destination } |
Dials a preview lead. See below. |
rc-adapter-ringcx-start-progressive-dial |
startRingCXProgressiveDial() |
{} |
Same as Start dialing on the Leads tab. Needs permissions.progressiveEnabled. When the agent is not available, the widget opens on the Leads tab and asks the agent to go available. |
rc-adapter-ringcx-stop-progressive-dial |
stopRingCXProgressiveDial() |
{} |
Same as Stop dialing on the Leads tab. |
Refused commands
Commands that need a ready session are not silently ignored when the session is not ready. The widget shows a message to the agent and posts rc-ringcx-agent-session-notify with the current status. Other refused or failed commands also show a message to the agent.
Set agent state. auxState picks one of the agent's aux states for state, as rc-ringcx-agent-state-notify reports them. Without it, the first aux state listed for state is used. A state the agent cannot choose is refused.
Control call. Actions apply to the current RingCX call, as the Agent tab controls do:
callAction |
Requirement |
|---|---|
hold, unhold, hangup, record or startRecord, stopRecord |
Follow the agent's call permissions. |
mute, unmute |
The integrated softphone. |
answer, reject |
The integrated softphone, with a call ringing there. |
dtmf |
The integrated softphone, and options.dtmf. |
Dial lead. lead can be the lead from rc-ringcx-lead-notify, its raw lead, or { leadId, campaignId }. With only leadId, the lead must be in the agent's current lead list. destination must be one of the lead's numbers, in its national or E.164 form; another number is not dialed.
New call. rc-adapter-new-call with callWith: 'ringcx' needs a ready session. While a RingCX call is active, rc-adapter-new-call without callWith: 'ringcx' is refused, and the widget asks the agent to finish the RingCX call first.
Message requests
These are request/response calls. Send rc-adapter-message-request, the same as other message requests. The reply is rc-adapter-message-response with responseId equal to your requestId.
| Path | Body | Response |
|---|---|---|
/ringcx/agent-session |
- | { status, agent, session, permissions }. Only { status } before RingCX has loaded. |
/ringcx/dispositions |
{ callId } |
{ callId, dispositions }: the dispositions the agent can pick for the call. { error } when the session is not ready. |
/get-call-log |
{ sessionId, source? } |
{ call }. Accepts a RingCX id in sessionId. |
const requestId = Date.now().toString();
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
type: 'rc-adapter-message-request',
requestId,
path: '/ringcx/agent-session',
}, '*');
window.addEventListener('message', (e) => {
const data = e.data;
if (data && data.type === 'rc-adapter-message-response' && data.responseId === requestId) {
console.log(data.response); // { status, agent, session, permissions }
}
});
Call logging
After a RingCX call, the agent wraps it up on one page in the Agent tab's side panel: the RingCX disposition and your call log form, with one Submit. The disposition is always saved to RingCX first; the CRM log follows.
Choose a logging mode
What you receive depends on your service registration:
| Your registration | Requests to callLoggerPath |
Your form on the wrap-up page |
|---|---|---|
callLoggerPrepareLogForm: true (recommended) |
prepareLogForm when the page opens, then logForm on Submit |
Yes, during the call or after it ends |
showLogModal: true |
logForm on Submit |
Yes, once the call has ended |
Neither (only callLoggerPath) |
callDisposition, sent automatically |
No, unless you open it yourself |
rc-ringcx-call-disposed-notify is posted in every mode.
Recommended: callLoggerPrepareLogForm: true
window.postMessage({
type: 'rc-adapter-register-third-party-service',
service: {
name: 'MyCRM',
callLoggerPath: '/callLogger',
callLogPageInputChangedEventPath: '/callLogger/inputChanged',
callLoggerPrepareLogForm: true,
},
}, '*');
- When the wrap-up page opens, during the call or after it ends, the widget sends
callLoggerPathonce withtriggerType: 'prepareLogForm'.call.ringcx.notesholds the notes typed so far. - Post your form with
rc-adapter-update-call-log-page, then answer{ data: 'ok' }. Do not navigate and do not log yet.- If you have no form for this call, answer
{ data: 'ok', noLogForm: '<short reason>' }. The page shows the reason instead of the form.
- If you have no form for this call, answer
- On Submit, the widget sends
triggerType: 'logForm'with the form data, as the log page does.- Answer
{ error: '<message>' }when the save failed. The disposition stays saved, and the page keeps the input with Retry and Log later. - No answer within 15 seconds counts as a failure.
- Answer
You never receive callDisposition in this mode. The form's note field follows the disposition Notes until the agent edits it; changes reach callLogPageInputChangedEventPath with keys: ['note'].
showLogModal: true
Without callLoggerPrepareLogForm, your current $LOG-CALL form, or the default form, shows on the wrap-up page once the call has ended. Submit sends logForm. No callDisposition is sent.
Only callLoggerPath
- Submitting a disposition logs the call right away with
triggerType: 'callDisposition'andredirect: true, whatever the widget's auto log setting. The widget does not open another page. Your handler decides from its own auto-log setting whether to open the CRM record. - A call without a disposition step is logged the same way when it ends, but only if Auto log is on in the widget settings.
- If you open your own log page for the call with
rc-adapter-navigate-toand/log/call/<id>?source=ringcx, your form shows on the call's wrap-up page instead of a separate page.
What the wrap-up page shows
- With both a disposition and your form: two pill tabs, Disposition and your service's
displayName(else itsname). - A call without a disposition step: only your form, in a tab named Log call.
- A call with dispositions and no log form: only the disposition.
- When only your form is left to save, its button uses your
uiSchema.submitButtonOptions.submitText, as the log page does, else Save.
Where the disposition data arrives
- Disposition:
call.ringcx.disposition. It is not a field of the log form. - Disposition notes:
call.ringcx.notes, and the prefillednoteon the default log page. A schema without anotefield still receives it oncall.ringcx.notes. - Call summary (AI generated or agent edited):
aiNoteon the request andcall.aiNote, the same field RingEX calls use for the AI note. It is absent when summaries are off for the session.
Edge cases
- Submit during the call. The disposition is saved right away. The
logFormsave is sent when the call ends, so the CRM gets the real duration. The wrap-up page comes back only when that save fails, or when the agent submitted before your form was shown. - Closing the page from your side. Use
rc-adapter-navigate-towithpath: 'goBack'or a target path. Going back never reopens a disposition that was already submitted for an ended call; the agent lands on the dialer instead. - A failing
callLoggerPath. The agent is not left in Pending Disposition. The call stays dispositioned and the log can be retried from history. When the widget logs the call itself (after a disposition, at call end, or from a history action), acallLoggerPaththat does not respond within 15 seconds shows a message in the widget.
Call history
RingCX history stays in the Agent tab. /unlogged-calls does not include RingCX calls.
- History rows use the host actions Log call, Edit log, and View log, with the same labels and
callLoggerTitleas RingEX rows. They sendtriggerTypecreateLog,editLog, andviewLog, and are hidden when nocallLoggerPathis registered. - The Logged / Unlogged status comes from
callLogEntityMatcherPathresults, as for RingEX rows. - Rows also show Refresh contact and the
callActionbuttons registered withbuttonEventPath. AcallActionclick sends the row asresourcein the call event shape, soresource.sourceis'ringcx'and RingCX fields are underresource.ringcx.
Contact matching
contactMatchPath receives the same body as for RingEX calls, { phoneNumbers, callerIds, triggerFrom? }, with plain phone numbers. The phone-plus-call-type match key of the standalone RingCX Embeddable is not used. The call type is on call.ringcx.callType.
Leads
The agent gets leads on the Leads tab of the Agent tab. Your page follows them with rc-ringcx-lead-notify and dials them with rc-adapter-ringcx-dial-lead.
- After a call dialed from a lead, preview or progressive, the widget goes back to the Leads tab once the call and its disposition are done.
- A number of a fetched lead that was already dialed cannot be dialed again, as in the standalone RingCX app.
Lead tab
The side panel's Lead tab shows a lead's name, numbers, and details. It opens:
- With each answered call that has a lead ID, next to the agent script and agent assistant. The script stays the active tab; the Lead tab is active only when the call has no script.
- When the agent selects View lead on the Leads tab or on the disposition page.
The agent can dial a number from the Lead tab under the same rules as the Leads tab, except in progressive dial mode. A call's Lead tab closes once the call and its disposition are done.
The Lead tab header has these actions:
| Action | Shown when | Effect |
|---|---|---|
| Edit | The lead's campaign lets agents update leads. | Opens an Update lead form. Saving updates the lead in RingCX and sends rc-ringcx-lead-notify with action: 'updated'. |
| Manual pass | The lead is from the Leads tab and the agent may pass leads. | Opens a Manual pass form. Passing sends rc-ringcx-lead-notify with action: 'passed'. |
| View lead | You registered leadViewerPath. |
Sends your leadViewerPath a request, so you can open the lead in your app. |
When the agent's RingCX permissions include lead history, the Lead tab also shows the lead's past dial attempts.
leadViewerPath request body: { lead, agentId }.
- For a lead from the Leads tab,
leadis the original RingCX lead, the same object asrawinrc-ringcx-lead-notify. - For a call's lead,
leadis the lead data from the call, merged with the matching Leads tab lead when there is one.
Lead tab details
- Details include source, lead state, passes, contact fields, IDs, aux data with the campaign's labels, and extra data. A field that holds a RingCX recording URL plays as audio.
- The call screen's side panel button lists the Lead tab with the other side panel tabs, and brings back any that are closed. On the disposition page, View lead brings back the call's Lead tab.
- A lead opened from the Leads tab switches to its call once that call is answered, and closes when the lead is passed or no longer fetched.
- Update lead edits contact fields, aux data, and numbers, one per line. Up to 6 numbers are kept, and each must be a valid number; national numbers are read as US numbers. When the campaign lets agents update everything but the numbers, the numbers cannot be changed.
- Manual pass follows the same rules as the Leads tab. The form closes when the lead is passed or no longer fetched, or when a RingCX call starts.
- Lead history loads when the agent selects Show history, then refreshes with Refresh. Each attempt shows its disposition and date in the agent's time zone, then its pass number, agent, agent disposition, and notes. For an attempt that left a voicemail, the notes list the audio that was played, grouped by audio library.
- In the Agent tab's history, a past lead call shows Call (disposition, call state, DNIS, termination party and reason), Lead (the lead as the call recorded it), and History (with lead history permission) tabs. Calls that are not lead calls show the call details only.
Progressive dialing
A progressive dial group is a RingCX Preview dial group with Enable progressive mode checked. With one in the session, rc-ringcx-agent-session-notify has permissions.progressiveEnabled: true, and the Leads tab shows Start dialing instead of Get leads.
- Start dialing (or
rc-adapter-ringcx-start-progressive-dial) asks the agent to go available when needed, and connects the agent's line. The line stays connected while the dialer runs. - The widget fetches leads and dials them one by one. Before each dial it waits the dial group's Progressive call delay, at most 120 seconds. It moves to the next lead once the call and its disposition are done. When no leads come back, it fetches again every 5 seconds.
- Stop dialing (or
rc-adapter-ringcx-stop-progressive-dial) stops the dialer and disconnects the line once no call is live. A manual call, an inbound call, choosing a state other than Available, a dial group change, or logging out also stops it.
While the dialer runs, agents cannot pick the lead or its number, so the Lead tab's numbers are not clickable; View lead and Manual pass stay available. If RingCX leaves the agent in another state after a call, such as Working, the widget asks the agent to go available: Go available resumes dialing, and Dismiss stops it.
Follow the dialer with rc-ringcx-progressive-dial-notify.
Voicemail drop
Experimental
Voicemail drop on RingCX calls is experimental.
With enableVoicemailDrop=1 and enableSideWidget=1, agents using the integrated softphone can drop a pre-recorded message on outbound RingCX calls. Unlike RingEX calls, the agent stays on the call until the message ends, and can take over if a person answers. See Voicemail drop on RingCX calls.
Migrating from the standalone RingCX Embeddable
| Standalone | This app |
|---|---|
rc-ev-ringCall |
rc-call-ring-notify |
rc-ev-newCall |
rc-call-start-notify |
rc-ev-endCall |
rc-call-end-notify |
rc-ev-sip* |
rc-webphone-connection-status-notify |
rc-ev-clickToDial |
rc-adapter-new-call with callWith: 'ringcx' |
rc-ev-dialLead |
rc-adapter-ringcx-dial-lead |
rc-ev-loadLeads, rc-ev-manualPassLead, rc-ev-callLead |
rc-ringcx-lead-notify with action loaded, passed, or dialed |
rc-ev-logout |
rc-adapter-ringcx-end-agent-session |
rc-ev-setEnvironment |
The appServer parameter; RingCX follows the RingCentral environment |
rc-ev-register |
rc-adapter-register-third-party-service |
rc-ev-matchContacts |
contactMatchPath |
rc-ev-matchCallLogs |
callLogEntityMatcherPath |
rc-ev-logCall |
callLoggerPath |
rc-ev-viewLead |
leadViewerPath |
rc-ev-sideWidgetOpenNotify |
rc-adapter-side-drawer-open-notify |
rc-ev-setSideWidgetExtended |
Not carried over. The host controls the drawer. |