Message Store Exports

Last updated: 2024-01-31Contributors
Edit this page

The message store exports API set allows you to archive message store data prior to it being deleted according to the enforcement of RingCentral’s data storage policy and compliance. The data includes message metadata and the actual content (attachments) of instant messaging, fax and voicemail.

RingCentral message store data retention rule is based on the account's setting:

Account Data Retention for Non-HIPAA Accounts

Data Duration Count/Size
Inbox (Fax / Voice Messages) -- 200 messages
Sent (Fax Messages) 30 days --
Outbox (Fax Messages) n/a n/a
Text Messages (SMS/MMS) No limit 5,000 messages per folder, per User (Inbox, Outbox, Sent, Deleted)

Account Data Retention for HIPAA enabled Accounts

Data Duration Count/Size
Inbox (Fax / Voice Messages) 30 days 200 messages
Sent (Fax Messages) 30 days --
Outbox (Fax Messages) n/a n/a
Text Messages (SMS/MMS) No limit 5,000 messages per folder, per User (Inbox, Outbox, Sent, Deleted)

Important

The message store exports APIs run at the account level. This means that only users with the admin role would be able to call these APIs and export the message store of all extensions in the entire account.

Message Store Exports APIs set

API path
Create Message Store Report /restapi/v1.0/account/~/message-store-report
Get Message Store Report Task /restapi/v1.0/account/~/message-store-report/taskId
Get Message Store Report Archive /restapi/v1.0/account/~/message-store-report/taskId/archive
Get Message Store Report Archive Content /restapi/v1.0/account/~/message-store-report/taskId/archive/archiveId

How to archive the message store data

There are 4 steps to archive your company message store using the APIs set:

1. Create a message store report task

To create a message store report task:

  • Define the period of time for the archive. The period of time is specified by the dateFrom and dateTo parameters in the body of the POST request.

  • Make a POST request to the /restapi/v1.0/account/~/message-store-report endpoint.

Required permission(s): ReadMessages

Upon successful API call completion, the response contains the id (taskId) and the status of the newly created task.

{
  uri: 'https://platform.devtest.ringcentral.com/restapi/v1.0/account/178009004/message-store-report/178009004-178009004-25464a39df3f4b4390801d80e5e13a01',
  id: '178009004-178009004-25464a39df3f4b4390801d80e5e13a01',
  status: 'Accepted',
  startTime: '2019-07-31T20:01:58Z',
  accountId: '178009004',
  dateFrom: '2019-01-01T00:00:00Z',
  dateTo: '2019-03-31T23:59:59.999Z'
}

2. Check the status of a task identified by the taskId

To archive a large message store report (for a long period of time or for an account with a large number of extensions), the report creation process may take several minutes to complete. Therefore, you should check the status of a task to ensure it is marked as “Completed” before you can proceed to get the report. The status of a task can be any of the following values:

Accepted - Pending - InProgress - AttemptFailed - Failed - Completed - Cancelled

To check the status of a task, make a GET request to /restapi/v1.0/account/~/message-store-report/[taskId] endpoint. Where the taskId is the value of the id returned in the previous step.

If the report is ready, the task status is marked as “Completed”.

Upon successful API call completion, the response contains the id (taskId) and the status of the newly created task.

{
  uri: 'https://platform.devtest.ringcentral.com/restapi/v1.0/account/178009004/message-store-report/178009004-178009004-25464a39df3f4b4390801d80e5e13a01',
  id: '178009004-178009004-25464a39df3f4b4390801d80e5e13a01',
  status: 'Completed',
  startTime: '2019-07-31T20:01:58Z',
  finishTime: '2019-07-31T20:02:11Z',
  accountId: '178009004',
  dateFrom: '2019-01-01T00:00:00Z',
  dateTo: '2019-03-31T23:59:59.999Z' }

3. Get the archive file URI.

When a task is created successfully and completed, make a GET request to the /restapi/v1.0/account/~/message-store-report/[taskId]/archive endpoint. Where the taskId is the value of the id returned in the previous step.

Upon successful API call completion, the response is a list of records. Each record contains the URI of the archival file and the size of that file.

{
  records: [
  {
    size: 14168,
    uri: 'https://platform.devtest.ringcentral.com/restapi/v1.0/account/178009004/message-store-report/178009004-178009004-ed6a473f3aea40819d761242fa6fa331/archive/0'
  },
  {
    size: 2152395,
    uri: 'https://platform.devtest.ringcentral.com/restapi/v1.0/account/178009004/message-store-report/178009004-178009004-ed6a473f3aea40819d761242fa6fa331/archive/1'
  } ]
}

4. Download the archive files.

The archival files are .zip compression files. To download the file, append a valid access token to the URI and make an HTTP GET request to the URI.

GET https://platform.devtest.ringcentral.com/restapi/v1.0/account/178009004/message-store-report/[taskId]]/archive/0
Authorization: Bearer [access_token]

The archival report is consisted of two main parts; the archived message metadata and the archived message attachments. If the size of the archived message attachments file is greater than 1GB, the system will generate multiple URIs for message attachment archival files, each file size is max 1GB.

The archived file at the index zero (archive/0) is always a .zip file containing message-store.json files. The files are organized under a folder structure which resembles the message store path to message metadata in RingCentral system:

/account/[accountId]/extension/[extensionId]/

The archived file at index one (archive/1) is a .zip file containing attachments of MMS or Fax messages, or voicemail binary file. The files are organized under a folder structure which resembles the message store path to message attachment in RingCentral system:

/account/[accountId]/extension/[extensionId]/message-store/content/[messageId]

Sample code to archive message store data

The following code sample shows how to call the Message Store Export APIs to export the message store data and save it to a local machine.

Running the code

  • If you have tried the SMS quick start, you can just copy all the functions below and add them to the quick start project then call the create_message_store_report() function. Otherwise, edit the variables in ALL CAPS with your app and user credentials before running the code.
  • If you run on your production account, remember to use app credentials for production and change the RingCentral server URL to "https://platform.ringcentral.com"
  • Also make sure that your use the JWT token of an admin user in order have enough user permission to export the message store.
const RC = require('@ringcentral/sdk').SDK

// Instantiate the SDK and get the platform instance
var rcsdk = new RC({
    server: "https://platform.devtest.ringcentral.com",
    clientId: "SANDBOX-APP-CLIENTID",
    clientSecret: "SANDBOX-APP-CLIENTSECRET"
});
var platform = rcsdk.platform();

/* Authenticate a user using a personal JWT token */
platform.login({ jwt: "SANDBOX-JWT" })
platform.on(platform.events.loginSuccess, function(e){
    create_message_store_report()
});

platform.on(platform.events.loginError, function(e){
    console.log("Unable to authenticate to platform. Check credentials.", e.message)
    process.exit(1)
});

/*
* Create a task to export the account messages within March 2023
*/
async function create_message_store_report() {
  try {
    var bodyParams = {
      dateFrom: "2023-03-01T00:00:00.000Z",
      dateTo: "2023-03-31T23:59:59.999Z"
    }
    var endpoint = "/restapi/v1.0/account/~/message-store-report"
    var resp = await platform.post(endpoint, bodyParams)
    var jsonObj = await resp.json()
    get_message_store_report_task(jsonObj.id)
  } catch (e) {
    console.log(e)
  }
}

/*
* Check the task completion status
*/
async function get_message_store_report_task(taskId) {
  try {
    var endpoint = `/restapi/v1.0/account/~/message-store-report/${taskId}`
    var resp = await platform.get(endpoint)
    var jsonObj = await resp.json()
    console.log(`Task creation status: ${jsonObj.status}`)
    if (jsonObj.status == "Completed") {
      get_message_store_report_archive(jsonObj.id)
    } else if ( jsonObj.status == "AttemptFailed" ||
                jsonObj.status == "Failed" ||
                jsonObj.status == "Cancelled" ) {
      console.log("Export message store failed.")
    } else {
      setTimeout(function() {
        get_message_store_report_task(taskId)
      }, 10000);
    }
  } catch (e) {
    console.log(e)
  }
}

/*
* When the task is completed, use the task id to get the uri of the report file
*/
async function get_message_store_report_archive(taskId) {
  console.log("Getting report uri ...")
  try {
    var endpoint = `/restapi/v1.0/account/~/message-store-report/${taskId}/archive`
    var resp = await platform.get(endpoint)
    var jsonObj = await resp.json()
    var date = new Date()
    for (var i = 0; i < jsonObj.records.length; i++) {
      var fileName = `message_store_content_${date.toISOString()}_${i}.zip`
      get_message_store_report_archive_content(jsonObj.records[i].uri, fileName)
    }
  } catch (e) {
    console.log(e)
  }
}

const fs    = require('fs')
const https = require('https')
const url = require('url')

async function get_message_store_report_archive_content(contentUri, fileName){
  var u = url.parse(contentUri)
  var tokenObj = await platform.auth().data()
  var accessToken = tokenObj.access_token
  download(u.host, u.path, accessToken, fileName, function(){
    console.log(`${fileName} file is saved to the local machine.`)
  })
}

const download = function(domain, path, accessToken, dest, cb) {
  var file = fs.createWriteStream(dest);
  var options = {
          host: domain,
          path: path,
          method: "GET",
          headers: {
            Authorization: `Bearer ${accessToken}`
          }
      }
  const req = https.request(options, res => {
    res.pipe(file);
    file.on('finish', function() {
      file.close(cb);
    });
  })
  req.on('error', error => {
    console.error(error)
  })
  req.end()
}
from ringcentral import SDK
from datetime import date
import requests
import time

#
# Create a task to export the account messages within March 2023
#
def create_message_store_report() :
    try:
        endpoint = "/restapi/v1.0/account/~/message-store-report"
        bodyParams = {
           'dateFrom': "2023-03-01T00:00:00.000Z",
           'dateTo': "2023-03-31T23:59:59.999Z"
        }
        response = platform.post(endpoint, bodyParams)
        json = response.json()
        get_message_store_report_task(json.id)
    except Exception as e:
        print (str(e))

#
# Check the task completion status
#
def get_message_store_report_task(taskId):
    try:
        endpoint = "/restapi/v1.0/account/~/message-store-report/" + taskId
        response = platform.get(endpoint)
        jsonObj = response.json()
        print(f'Task creation status: {jsonObj.status}')
        if jsonObj.status == "Completed":
            return get_message_store_report_archive(taskId)
        elif (jsonObj.status == "AttemptFailed" or jsonObj.status == "Failed" or jsonObj.status == "Cancelled"):
            print ("Export message store failed.")
        else:
            time.sleep(10)
            get_message_store_report_task(taskId)
    except Exception as e:
        print (str(e))

#
# When the task is completed, use the task id to get the uri of the report file
#
def get_message_store_report_archive(taskId):
    print("Getting report uri ...")
    try:
        endpoint = "/restapi/v1.0/account/~/message-store-report/"+ taskId +"/archive"
        response = platform.get(endpoint)
        jsonObj = response.json()
        today = date.today()
        dateLog = today.strftime("%Y_%m_%d_%H_%M")
        for i in range( len(jsonObj.records) ):
            fileName = f'message_store_{dateLog}_{i}.zip'
            get_message_store_report_archive_content(jsonObj.records[i].uri, fileName)
    except Exception as e:
        print (str(e))


def get_message_store_report_archive_content(contentUri, fileName):
    uri = platform.create_url(contentUri, False, None, True);
    response = requests.get(uri, stream=True)
    with open(fileName,"wb") as output:
        output.write(response.content)

    print (f'{fileName} file is saved to the local machine.')


# Authenticate a user using a personal JWT token
def login():
    try:
      platform.login( jwt= "SANDBOX_JWT" )
      create_message_store_report()
    except Exception as e:
      print ("Unable to authenticate to platform. Check credentials." + str(e))

# Instantiate the SDK and get the platform instance
rcsdk = SDK("SANDBOX-APP-CLIENTID", "SANDBOX-APP-CLIENTSECRET", "https://platform.devtest.ringcentral.com")
platform = rcsdk.platform()

login()
<?php
require('vendor/autoload.php');

// Instantiate the SDK and get the platform instance
$rcsdk = new RingCentral\SDK\SDK( "SANDBOX-APP-CLIENTID", "SANDBOX-APP-CLIENTSECRET", "https://platform.devtest.ringcentral.com" );
$platform = $rcsdk->platform();

/* Authenticate a user using a personal JWT token */
try {
  $platform->login(["jwt" => "SANDBOX-JWT"]);
}catch (\RingCentral\SDK\Http\ApiException $e) {
  // Getting error messages using PHP native interface
  print 'Expected HTTP Error: ' . $e;
  exit ("Error message: " . $e->apiResponse->response()->error() . PHP_EOL;
}
create_message_store_report();

/*
* Create a task to export the account messages within March 2023
*/
function create_message_store_report(){
  global $platform;
  try {
    $bodyParams = array(
        'dateFrom' => "2023-03-01T00:00:00.000Z",
        'dateTo' => "2023-03-31T23:59:59.999Z",
    );
    $endpoint = "/account/~/message-store-report";
    $response = $platform->post($endpoint, $bodyParams);
    $jsonObj = $response->json();
    get_message_store_report_task($jsonObj->id);
  }catch (\RingCentral\SDK\Http\ApiException $e) {
    // Getting error messages using PHP native interface
    print 'Expected HTTP Error: ' . $e;
    print ("Error message: " . $e->apiResponse->response()->error() . PHP_EOL);
  }
}

/*
* Check the task completion status
*/
function get_message_store_report_task($taskId){
  global $platform;
  try {
    $endpoint = "/account/~/message-store-report/" . $taskId;
    $response = $platform->get($endpoint);
    $jsonObj = $response->json();
    print ("Task creation status: " . $jsonObj->status . PHP_EOL);
    if ($jsonObj->status == "Completed"){
        get_message_store_report_archive($jsonObj->id);
    } else if ( $jsonObj->status == "AttemptFailed" ||
                $jsonObj->status == "Failed" ||
                $jsonObj->status == "Cancelled" ) {
      print ("Export message store failed.");
    } else {
        sleep(10);
        get_message_store_report_task($taskId);
      }
  } catch (\RingCentral\SDK\Http\ApiException $e) {
    // Getting error messages using PHP native interface
    print 'Expected HTTP Error: ' . $e;
    print ("Error message: " . $e->apiResponse->response()->error() . PHP_EOL);
  }
}

/*
* When the task is completed, use the task id to get the uri of the report file
*/
function get_message_store_report_archive($taskId){
  global $platform;
  print ("Getting report uri ...\n");
  try {
    $endpoint = "/account/~/message-store-report/" . $taskId . "/archive";
    $response = $platform->get($endpoint);
    $jsonObj = $response->json();
    for ($i=0; $i < count($jsonObj->records); $i++){
      $fileName = "message_store_content_" . date("Y_m_d_H_i", time()) . "_" . $i . ".zip";
      get_message_store_report_archive_content($jsonObj->records[$i]->uri, $fileName);
    }
  } catch (\RingCentral\SDK\Http\ApiException $e) {
    // Getting error messages using PHP native interface
    print 'Expected HTTP Error: ' . $e;
    print ("Error message: " . $e->apiResponse->response()->error() . PHP_EOL);
  }
}

function get_message_store_report_archive_content($contentUri, $fileName){
  global $platform;
  $uri = $platform->createUrl($contentUri, array(
    'addServer' => false,
    'addMethod' => 'GET',
    'addToken'  => true
  ));
  $dest = $fileName;
  file_put_contents($dest, fopen($uri, 'r'));
  print ($fileName . " file is saved to the local machine." . PHP_EOL);
}
require 'ringcentral'
require "down"
require "fileutils"

#
# Create a task to export the account messages within March 2023
#
def create_message_store_report()
  begin
    bodyParams = {
      dateFrom: "2023-03-01T00:00:00.000Z",
      dateTo: "2023-03-31T23:59:59.999Z"
    }
    endpoint = "/restapi/v1.0/account/~/message-store-report"
    response = $platform.post(endpoint, payload: bodyParams)
    puts (response.body['id'])
    get_message_store_report_task(response.body['id'])
  rescue StandardError => e
    puts (e)
  end
end

#
# Check the task completion status
#
def get_message_store_report_task(taskId)
  begin
    endpoint = "/restapi/v1.0/account/~/message-store-report/" + taskId
    resp = $platform.get(endpoint)
    taskStatus = resp.body['status']
    puts ("Task creation status: " + taskStatus)
    if taskStatus == "Completed"
      get_message_store_report_archive(taskId)
    elsif (taskStatus == "AttemptFailed" || taskStatus == "Failed" || taskStatus == "Cancelled")
      puts ("Export message store failed.")
    else
      sleep(10)
      get_message_store_report_task(taskId)
    end
  rescue StandardError => e
    puts (e)
  end
end

#
# When the task is completed, use the task id to get the uri of the report file
#
def get_message_store_report_archive(taskId)
  puts "Getting report uri ..."
  begin
    endpoint = "/restapi/v1.0/account/~/message-store-report/"+ taskId +"/archive"
    resp = $platform.get(endpoint)
    length = resp.body['records'].length
    dateLog = Time.now.strftime("%Y_%m_%d_%H_%M")
    for i in (0...length)
        fileName = "message_store_" + dateLog + "_" + i.to_s + ".zip"
        get_message_store_report_archive_content(resp.body['records'][i]['uri'], fileName)
    end
  rescue StandardError => e
    puts (e)
  end
end

def get_message_store_report_archive_content(contentUri, fileName)
  begin
    uri = contentUri + "?access_token=" + $platform.token['access_token']
    tempfile = Down.download(uri)
    FileUtils.mv(tempfile.path, fileName)
    puts (fileName + " file is saved to the local machine.")
  rescue StandardError => e
    puts (e)
  end
end


# Authenticate a user using a personal JWT token
def login()
  begin
    $platform.authorize( jwt: "SANDBOX_JWT" )
    create_message_store_report()
  rescue StandardError => e
    puts ("Unable to authenticate to platform. Check credentials." + e.to_s)
  end
end

# Instantiate the SDK and get the platform instance
$platform = RingCentral.new( "SANDBOX-APP-CLIENTID", "SANDBOX-APP-CLIENTSECRET", "https://platform.devtest.ringcentral.com" )

login()
using System;
using System.Threading.Tasks;
using RingCentral;

namespace Export_MessageStore
{
    class Program
    {
        static RestClient restClient;
        static async Tast Main(string[] args)
        {
            try
            {
              // Instantiate the SDK
              restClient = new RestClient( "SANDBOX-APP-CLIENTID", "SANDBOX-APP-CLIENTSECRET", "https://platform.devtest.ringcentral.com");
              // Authenticate a user using a personal JWT token
              await restClient.Authorize("SANDBOX_JWT");

              await create_message_store_report();
            }
            catch (Exception ex)
            {
              Console.WriteLine(ex.Message);
            }
        }
        /*
        * Create a task to export the account messages within March 2023
        */
        static private async Task create_message_store_report()
        {
            var bodyParams = new CreateMessageStoreReportRequest();
            bodyParams.dateFrom = "2023-03-01T00:00:00.000Z";
            bodyParams.dateTo = "2023-03-31T23:59:59.999Z";

            var response = await restClient.Restapi().Account().MessageStoreReport().Post(bodyParams);
            await get_message_store_report_task(response.id);
        }
        /*
        * Check the task completion status
        */
        static private async Task get_message_store_report_task(String taskId)
        {
            var response = await restClient.Restapi().Account().MessageStoreReport(taskId).Get();
            Console.WriteLine("Task creation status: " + response.status);
            if (response.status == "Completed")
            {
                await get_message_store_report_archive(taskId);
            }
            else if ( response.status == "AttemptFailed" ||
                      response.status == "Failed" ||
                      response.status == "Cancelled")
            {
                Console.WriteLine("Export message store failed.");
            }
            else
            {
                Thread.Sleep(10000);
                await get_message_store_report_task(taskId);
            }
        }
        /*
        * When the task is completed, use the task id to get the uri of the report file
        */
        static private async Task get_message_store_report_archive(String taskId)
        {
            Console.WriteLine("Getting report uri ...");
            var resp = await restClient.Restapi().Account().MessageStoreReport(taskId).Archive().List();
            DateTime value = DateTime.Now;
            var dateStr = value.ToString("yyyy-MM-dd-HH_mm");
            for (var i = 0; i < resp.records.Length; i++)
            {
                var fileName = "message_store_content_" + dateStr + "_" + i + ".zip";
                var contentUrl = resp.records[i].uri + "?access_token=" + restClient.token.access_token;
                WebClient webClient = new WebClient();
                webClient.DownloadFile(contentUrl, fileName);
                Console.WriteLine(fileName + " file is saved to the local machine.");
            }
        }
    }
}
package Export_MessageStore;

import com.ringcentral.*;
import com.ringcentral.definitions.*;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import java.text.SimpleDateFormat;

public class Export_MessageStore {
    static RestClient restClient;

    public static void main(String[] args) {
        // Instantiate the SDK
        restClient = new RestClient( "SANDBOX-APP-CLIENTID", "SANDBOX-APP-CLIENTSECRET", "https://platform.devtest.ringcentral.com");
        var obj = new Export_MessageStore();
        try {
          // Authenticate a user using a personal JWT token
          restClient.authorize( "SANDBOX_JWT" );
          obj.create_message_store_report();
        } catch (RestException | IOException e) {
          e.printStackTrace();
        }
    }

    /*
    * Create a task to export the account messages within March 2023
    */
    public void create_message_store_report() throws RestException, IOException{
        var bodyParams = new CreateMessageStoreReportRequest();
        bodyParams.dateFrom = "2023-03-01T00:00:00.000Z";
        bodyParams.dateTo = "2023-03-31T23:59:59.999Z";

        var response =  restClient.restapi().account().messageStoreReport().post(bodyParams);
        get_message_store_report_task(response.id);
    }
    /*
    * Check the task completion status
    */
    private void get_message_store_report_task(String taskId) throws RestException, IOException {
        var response = restClient.restapi().account().messageStoreReport(taskId).get();
        System.out.println("Task creation status: " + response.status);
        if (response.status.equals("Completed")) {
            get_message_store_report_archive(taskId);
        } else if ( response.status.equals("AttemptFailed") ||
                     response.status.equals("Failed") ||
                     response.status.equals("Cancelled") ) {
            System.out.println("Export message store failed.");
        } else {
            try {
                Thread.sleep(5000);
                get_message_store_report_task(taskId);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /*
    * When the task is completed, use the task id to get the uri of the report file
    */
    private void  get_message_store_report_archive(String taskId) throws RestException, IOException {
        System.out.println("Getting report uri ...");
        SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd-HH_mm");
        Date date = new Date(System.currentTimeMillis());
        var dateStr = formatter.format(date);
        var resp = restClient.restapi().account().messageStoreReport(taskId).archive().list();
        for (var i = 0; i < resp.records.length; i++) {
            var fileName = "./src/test/resources/message_store_content_" + dateStr + "_" + i + ".zip";
            var contentUrl = resp.records[i].uri + "?access_token=" + restClient.token.access_token;
            try (BufferedInputStream inputStream = new BufferedInputStream(new URL(contentUrl).openStream());
                  FileOutputStream fileOS = new FileOutputStream(fileName)) {
                     byte data[] = new byte[1024];
                     int byteContent;
                     while ((byteContent = inputStream.read(data, 0, 1024)) != -1) {
                       fileOS.write(data, 0, byteContent);
                     }
                     System.out.println(fileName + " file is saved to the local machine.");
            } catch (IOException e) {
                 // handles IO exceptions
            }
        }
    }
}

Relevant APIs for Further Reading