Use Message Sync API to archive your SMS, Fax and Voicemail Messages

message sync

Messages are not just critical for the modern day business, but extremely useful in ensuring quality and customer satisfaction. With RingCentral’s API, you can easily retrieve message data for analysis, archival and compliance. The API provides access to all messages include voicemail, SMS and fax.

RingCentral’s Message Store API provides a common way to access message data and is often used with time filters to retrieve data on a periodic basis. The Message Sync API is an alternate way to retrieve the same data with an easier approach using a sync token. When calling the API with a sync token, you will receive new and updated messages from your previous sync, easing the retrieval process. RingCentral uses and recommends the Message Sync API for efficient syncing purposes.

This article will show how to sync all your messages data from RingCentral using our Data API using a demo app. You can also find the source code in this Github Repo.


  1. A free RingCentral Developer account to create a RingCentral app
  2. Node.js with version ≥ 8
  3. NPM or yarn

Create a new RingCentral app

Before we can use the RingCentral API, we will need to create or login to our RingCentral Developers account and create an app. To create an app, follow the steps in this tutorial.

Step 2: Choose Your App Type & Platform Type

Next, you need to choose Private and Server-only (No UI) type. This will enable your app to use the Password flow Authorization flow. We will run our code in a Node.js server.


Step 3: Add Permissions

Add Read Messages and Webhook Subscriptions permissions to your app.

Setup the Demo App

$ git clone
$ cd ringcentral-message-sync-demo

Create a .env file in project root path with your app and user credentials:

RINGCENTRAL_SERVER_URL=your_ringcentral_app_server, eg:
RINGCENTRAL_EXTENSION=your_ringcentral_extension, eg: 101

Start the server:

$ yarn start

How the App works

First, the app uses the RingCentral JS SDK to handle authorization.

async function initSDK() {
let authorizationData;
if (fs.existsSync(authorizationFilePath)) {
authorizationData = JSON.parse(fs.readFileSync(authorizationFilePath, 'utf-8'));
rcsdk = new RingCentral({
appKey: process.env.RINGCENTRAL_CLIENT_ID,
appSecret: process.env.RINGCENTRAL_CLIENT_SECRET,
server: process.env.RINGCENTRAL_SERVER_URL
// set authorization token to sdk
if (authorizationData) {
} else {
try {
const response = await rcsdk.platform().login({
username: process.env.RINGCENTRAL_USERNAME,
extension: process.env.RINGCENTRAL_EXTENSION,
password: process.env.RINGCENTRAL_PASSWORD,
fs.writeFileSync(authorizationFilePath, JSON.stringify(response.json(), null, 2));
} catch (e) {
console.error('loginFail:', e.message);
throw e;
rcsdk.platform().addListener('refreshSuccess', () => {
const tokenData = rcsdk.platform().auth().data();
fs.writeFileSync(authorizationFilePath, JSON.stringify(tokenData, null, 2));

Next, the app uses the Message Sync API to fetch messages from RingCentral Platfrom.

async function syncMessages() {
let syncInfo;
if (fs.existsSync(syncInfoFilePath)) {
syncInfo = JSON.parse(fs.readFileSync(syncInfoFilePath, 'utf-8'));
let syncParams;
if (!syncInfo) {
// Full sync in first time without syncToken
const dateFrom = new Date();
dateFrom.setDate(dateFrom.getDate() - 30);
syncParams = {
syncType: 'FSync',
dateFrom: dateFrom.toISOString(),
} else {
syncParams = {
syncToken: syncInfo.syncToken,
syncType: 'ISync'
try {
const response = await rcsdk.platform().get('/restapi/v1.0/account/~/extension/~/message-sync', syncParams);
const newData = response.json();
syncInfo = newData.syncInfo;
fs.writeFileSync(syncInfoFilePath, JSON.stringify(syncInfo, null, 2));
let messages = [];
if (fs.existsSync(messagesFilePath)) {
messages = JSON.parse(fs.readFileSync(messagesFilePath, 'utf-8'));
if (newData.records && newData.records.length > 0) {
messages = messages.concat(newData.records);
fs.writeFileSync(messagesFilePath, JSON.stringify(messages, null, 2));
} catch (e) {
console.error('syncFail:', e.message);

The first time the app syncs the data we need to perform a full sync using the Fsync sync type to get the base data. After that, we can use a syncToken to perform incremental sync using the Isync sync type to retrieve new and updated data.

The max number of messages that sync endpoint returns is 250. When there are records more than 250, it will only return newest 250 records. If there are older records the olderRecordsExist property will be present and, to get older requests, we can make requests setting the dateTo property as the earliest date in our response. Following is example code shows how to handle this.

async function syncAPI(params) {
const response = await rcsdk.platform().get('/restapi/v1.0/account/~/extension/~/message-sync', params);
const { records, syncInfo } = response.json();
if (!syncInfo.olderRecordsExist || records.length === 0) {
return { records, syncInfo };
const oldestCreationTime = (new Date(records[records.length - 1].creationTime)).toISOString();
const {
} = params;
const oldData = await syncAPI({
dateTo: oldestCreationTime
return {
records: records.concat(oldData.records),

For this demo, we sync messages every 5 minutes. But you can use a Webhook to keep your data up-to-date.

More Information

You can get more information on the message sync API from the API Reference:

Hopefully this article was helpful. Please let us know what you think by leaving your questions and comments below.