Obtaining a RingCX access token with a RingCentral Login
This is the default authentication flow for current RingCX Voice API integrations. It applies when the RingCX user signs in with a linked RingCentral / RingEX login.
The flow has two steps:
- Obtain a RingCentral access token from the RingCentral platform.
- Exchange that RingCentral access token for a RingCX access token.
Use the RingCX access token, not the original RingCentral access token, when you call RingCX Voice APIs.
RingCX Voice APIs are rooted at: https://engage.ringcentral.com/voice/api/
Create an app
Create an app in the RingCentral Developer Portal. You can use the "Create RingCX App" button below, enter a name and description if needed, and click "Create". If you do not have a RingCentral account, you will be prompted to create one.
Important
You need a production RingCentral account that is linked to your RingCX account. A RingCentral account created only in the Developer Portal will not provide access to production RingCX Voice APIs.
When you are done, you will be taken to the app's dashboard. Save the Client ID and Client Secret. You will use them to authenticate with RingCentral in the next step.
Retrieve a RingCentral access token
Use the RingCentral authentication flow configured for your app to retrieve a RingCentral access token. For server-side RingCX integrations, JWT auth is the recommended RingCentral auth flow.
See the RingCentral authentication guide for the current RingCentral OAuth instructions.
The RingCentral access token proves the RingCentral user/app identity. It is not the token you send to RingCX Voice API endpoints. After you retrieve it, exchange it for a RingCX access token.
Retrieve a RingCX access token
Call the RingCX token exchange endpoint with the RingCentral access token.
The token exchange and refresh endpoints are authentication endpoints. The examples below use the Engage auth host. After you have a RingCX access token, use the RingCX Voice API host for API calls.
Request
POST https://engage.ringcentral.com/api/auth/login/rc/accesstoken?includeRefresh=true
Content-Type: application/x-www-form-urlencoded
rcAccessToken=<ringCentralAccessToken>&rcTokenType=Bearer
Where:
<ringCentralAccessToken>is the RingCentral access token returned by the RingCentral authentication flow.rcTokenTypemust beBearer.includeRefresh=trueincludes a RingCXrefreshTokenin the response.
curl -X POST 'https://engage.ringcentral.com/api/auth/login/rc/accesstoken?includeRefresh=true' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'rcAccessToken=<ringCentralAccessToken>' \
-d 'rcTokenType=Bearer'
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
)
// RingCXToken is an example and does not cover all the
// properties in the API response.
type RingCXToken struct {
AccessToken string `json:"accessToken"`
TokenType string `json:"tokenType"`
}
func RcToRingCXToken(rctoken string) (string, error) {
res, err := http.PostForm(
"https://engage.ringcentral.com/api/auth/login/rc/accesstoken?includeRefresh=true",
url.Values{"rcAccessToken": {rctoken}, "rcTokenType": {"Bearer"}})
if err != nil {
return "", err
}
defer res.Body.Close()
if res.StatusCode >= 300 {
return "", fmt.Errorf("Invalid Token Response [%v]", res.StatusCode)
}
ringCXToken := RingCXToken{}
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", err
}
err = json.Unmarshal(bytes, &ringCXToken)
return ringCXToken.AccessToken, err
}
func main() {
rctoken := "VALID-RINGCENTRAL-ACCESS-TOKEN"
ringcxToken, err := RcToRingCXToken(rctoken)
if err != nil {
log.Fatal(err)
}
fmt.Println(ringcxToken)
}
var https = require('https')
var querystring = require('querystring')
var RC_ACCESS_TOKEN = "VALID-RINGCENTRAL-ACCESS-TOKEN"
var url = "engage.ringcentral.com"
var path = '/api/auth/login/rc/accesstoken?includeRefresh=true'
var body = querystring.stringify({
rcAccessToken: RC_ACCESS_TOKEN,
rcTokenType: 'Bearer'
})
var headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(body)
}
var options = {host: url, path: path, method: 'POST', headers: headers};
var post_req = https.request(options, function(res) {
var response = ""
res.on('data', function (chunk) {
response += chunk
}).on("end", function(){
if (res.statusCode == 200){
var tokensObj = JSON.parse(response)
console.log(tokensObj.accessToken)
}else{
console.log(response)
}
});
}).on('error', function (e) {
console.log(e)
})
post_req.write(body);
post_req.end();
import json
import requests
RC_ACCESS_TOKEN = "VALID-RINGCENTRAL-ACCESS-TOKEN"
url = "https://engage.ringcentral.com/api/auth/login/rc/accesstoken?includeRefresh=true"
body = {
"rcAccessToken": RC_ACCESS_TOKEN,
"rcTokenType": "Bearer"
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
try:
res = requests.post(url, headers=headers, data=body)
if res.status_code == 200:
jsonObj = json.loads(res.content)
print (jsonObj['accessToken'])
else:
print (res.content)
except Exception as e:
raise ValueError(e)
<?php
$RC_ACCESS_TOKEN = "VALID-RINGCENTRAL-ACCESS-TOKEN";
$url = "https://engage.ringcentral.com/api/auth/login/rc/accesstoken?includeRefresh=true";
$body = http_build_query(array(
'rcAccessToken' => $RC_ACCESS_TOKEN,
'rcTokenType' => 'Bearer'
));
$headers = array ('Content-Type: application/x-www-form-urlencoded');
try{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
$strResponse = curl_exec($ch);
$curlErrno = curl_errno($ch);
if ($curlErrno) {
throw new Exception($curlErrno);
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200) {
$tokensObj = json_decode($strResponse);
print ($tokensObj->accessToken);
}else{
print ($strResponse);
}
}
}catch (Exception $e) {
throw $e;
}
Response
The response contains the RingCX accessToken that you use for RingCX Voice API calls. If you include includeRefresh=true, the response also contains a refreshToken that can be used to obtain a new RingCX access token.
Save the following values:
accessToken: The RingCX bearer token for API requests.refreshToken: The RingCX refresh token, returned whenincludeRefresh=true.mainAccountIdand account IDs inagentDetails: Useful when choosing the account or sub-account for API calls.
The following is an abbreviated response.
{
"refreshToken":"<rcRingCXRefreshToken>",
"accessToken":"<rcRingCXAccessToken>",
"tokenType":"Bearer",
"mainAccountId":"333333",
"agentDetails":[
{
"agentId":111111,
"firstName":"John",
"lastName":"Wang",
"email":"john.wang@example.com",
"username":"john.wang@example.com",
"agentType":"AGENT",
"rcUserId":222222,
"accountId":"333333",
"accountName":"RingForce",
"agentGroupId":null,
"allowLoginControl":true,
"allowLoginUpdates":true
}
],
"adminId":1111,
"adminUrl":"/voice/admin/",
"agentUrl":"/voice/agent/",
"ssoLogin":true
}
Token lifetime and rate limits
RingCX access tokens expire after 5 minutes. The token exchange endpoint is limited to 5 requests per minute.
Do not request a new RingCX access token before every API call. Cache and reuse the token until it is close to expiration, then obtain a new token. If your application has multiple workers or servers, coordinate token renewal so they do not all try to re-authenticate at the same time.
RingCX does not automatically refresh the token for you. If an API call returns 401 Unauthorized because the token expired, your application must obtain a new valid RingCX token before retrying the request.
Example RingCX API call
Use the RingCX access token in the Authorization header.
GET https://engage.ringcentral.com/voice/api/v1/admin/users
Authorization: Bearer <ringcxAccessToken>
Get accounts
You can retrieve the RingCX accounts available to the authenticated user. This request uses the RingCX access token returned by the token exchange.
GET https://engage.ringcentral.com/voice/api/v1/admin/accounts
Authorization: Bearer <ringcxAccessToken>
Here is an example cURL command:
curl -X GET 'https://engage.ringcentral.com/voice/api/v1/admin/accounts' \
-H 'Authorization: Bearer <ringcxAccessToken>'
The response includes the RingCX account IDs you need for RingCX Voice API requests:
accountIdis the RingCX sub-account ID. Most operational API calls are performed against a sub-account.mainAccountIdis the RingCX main account ID. The main account is the top-level account.
Some RingCX APIs also require the RingCentral account UID. To retrieve that value, call the RingCentral account endpoint with the RingCentral/RingEX access token from Retrieve a RingCentral access token.
GET https://platform.ringcentral.com/restapi/v1.0/account/~
Authorization: Bearer <ringCentralAccessToken>
In that response, the id value is the RingCentral account UID. Use the RingCentral/RingEX access token for this request, not the RingCX access token.
Refresh a RingCX access token
If you requested a refresh token with includeRefresh=true, call the refresh endpoint to obtain a new RingCX access token.
Request
POST https://engage.ringcentral.com/api/auth/token/refresh
Content-Type: application/x-www-form-urlencoded
refresh_token=<ringcxRefreshToken>
Where:
<ringcxRefreshToken>is the RingCX refresh token returned by the token exchange or previous refresh response.
Response
The response contains a new accessToken and a new refreshToken. Save the new refresh token for the next refresh request.
The following is an abbreviated response.
{
"refreshToken":"<newRcRingCXRefreshToken>",
"accessToken":"<rcRingCXAccessToken>",
"tokenType":"Bearer",
"mainAccountId":"333333",
"agentDetails":[
{
"agentId":111111,
"firstName":"John",
"lastName":"Wang",
"email":"john.wang@example.com",
"username":"john.wang@example.com",
"agentType":"AGENT",
"rcUserId":222222,
"accountId":"333333",
"accountName":"RingForce",
"agentGroupId":null,
"allowLoginControl":true,
"allowLoginUpdates":true
}
],
"adminId":1111,
"adminUrl":"/voice/admin/",
"agentUrl":"/voice/agent/",
"ssoLogin":true
}
If you did not request or store a refresh token, repeat the RingCentral-token-to-RingCX-token exchange with a valid RingCentral access token.
If the RingCX access token is expired, API requests may return:
401 Unauthorized
Jwt is expired