RingCentral Team Messaging Compliance Exports

Last updated: 2024-02-08Contributors
Edit this page

Compliance Exports is a special capability specifically built for companies and regulated industries, such as financial services and health care, with compliance requirements for using electronic communication in the workplace. This feature is also a fail-safe way of preserving business communications for compliance and legal discovery or internal review.

Admin priveleges are required to call the Compliance Export APIs

The Compliance Export APIs run at the account level. This means that only users with the admin role are permitted to call these APIs in order to export the data of all users in the entire account.

The Compliance Exports feature must be turned on from the RingCentral App in the Administration settings.

RingCentral's Data Retention Policy

The Compliance Export API allows any data retention practices to be automated and is essential for regulated industries because RingCentral does not retain customer data indefinitely. Our data retention policy is as follows, depending upon whether your account is "HIPAA enabled" (please consult your account representative or support to inquire about your account settings).

Account Data Retention Rule
Non-HIPAA The account admin can set the retention policy to one of the following: 30, 60 and 90 days. Once a policy is set, on a nightly basis all content older than the specified number of days will be deleted permanently.
HIPAA enabled All data will be deleted after 30 days.

Changing your data retention policy

The RingCentral App provides admins with a way of modifying your account's data retention policy. Login to RingCentral App, and navigate to the Settings area. Then select "Administration." There you will see "Manage data retention policy."

Team Messaging Data Export Process

Team Messaging Exports can take some time to compile and make available for download. Therefore, the process is an asynchronous one that follows this simple 3-step flow:

  1. Developer creates an "Export Report" task.
  2. Developer polls to check the status of the created "Export Report" task.
  3. When the task is complete, developer downloads the generated file.

What follows is a more detailed walk-through of this process.

Creating an Export Report Task

A compliance export task can be created by administrators inside of the RingCentral client under the Administration section.

This is helpful to human beings, but is difficult to automate. To create an export task via the API one would need to:

  • Specify the period of time for the archive via the timeFrom and timeTo parameters.
  • Specify a list of users whose data you would like to export via the contacts parameter. A contact is an object and can be specified by an id number or an email address.
  • Specify a list of teams/conversations to export via the chatIds parameter.
  • Finally, make a POST request to the /team-messaging/v1/data-export endpoint.

How to find IDs to filter by

Valid chatIds can be retrieved using the Get Chats API to read all teams/chats/conversations.

Required permission(s): Team Messaging

If successful, the response will contain the task ID and the status of the newly created task as shown below.

{
  "uri":"https://platform.ringcentral.com/team-messaging/v1/data-export/809646016-xx-yy",
  "id":"809646016-xx-yy",
  "creationTime":"2020-01-16T22:12:55Z",
  "lastModifiedTime":"2020-01-16T22:12:55Z",
  "status":"Accepted",
  "creator": {
    "id":"62288329016",
    "firstName":"Paco",
    "lastName":"Vu"},
  "specific": {
    "timeFrom":"2020-01-14T00:00:00Z",
    "timeTo":"2020-01-16T22:12:55Z"
  }
}

Polling the Status of the Export Task

To archive a large data export 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 will need to periodically check the status of a task. When its status is marked as "Completed" 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 /team-messaging/v1/data-export/[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."

When successful, the response will contain the id (taskId) and the status of the newly created task.

{
  "uri":"https://platform.ringcentral.com/team-messaging/v1/data-export/809646016-xx-yy",
  "id":"809646016-xx-yy",
  "creationTime":"2020-01-16T22:12:55Z",
  "lastModifiedTime":"2020-01-16T22:12:55Z",
  "status":"Completed",
  "creator": {
    "id":"62288329016",
    "firstName":"Paco",
    "lastName":"Vu"},
  "specific": {
    "timeFrom":"2020-01-14T00:00:00Z",
    "timeTo":"2020-01-16T22:12:55Z"
    },
  "datasets":[
    {
      "id":"1",
      "size":3434,
      "uri":"https://media.ringcentral.com/team-messaging/v1/data-export/809646016-xx-yy/datasets/1"
    }]
}

Authentication and file downloads

When an export task has completed successfully, make a GET request to the uri parameter returned in the response as described in the previous step, and pass your access token via an Authorization header or access_token query parameter as described in Accessing protected content on Working with media content.

Sample Code: Export Team Messaging Data

The following code sample shows how to call the Compliance Export API to export the team messaging data and save it to a local machine.

Running the code

  • If you have tried the Team Messaging quick start, you can just copy all the functions below and add them to the quick start project then call the create_compliance_export_task() 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"
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, () => {
    create_compliance_export_task()
})

/*
* Create a task to export the Team Messaging store for a period of time.
*/
async function create_compliance_export_task() {
  console.log("Create export task.")
  try {
    let bodyParams = {
        timeFrom: "2023-01-01T00:00:00.000Z",
        timeTo: "2023-01-31T23:59:59.999Z"
    }
    let endpoint = "/team-messaging/v1/data-export"
    var resp = await platform.post(endpoint, bodyParams)
    var jsonObj = await resp.json()
    get_compliance_export_task(jsonObj.id)
  } catch (e) {
      console.log(e.message)
  }
}

/*
* Check the status of the task using the taskId.
*/
async function get_compliance_export_task(taskId) {
  console.log("Check export task status ...")
  try {
    let endpoint = `/team-messaging/v1/data-export/${taskId}`
    var resp = await platform.get(endpoint)
    var jsonObj = await resp.json()
    if (jsonObj.status == "Completed") {
      for (var i = 0; i < jsonObj.datasets.length; i++) {
        var fileName = `rc-export-reports-${jsonObj.creationTime}_${i}.zip`
        get_report_archive_content(jsonObj.datasets[i].uri, fileName)
      }
    } else if (jsonObj.status == "Accepted" || jsonObj.status == "InProgress") {
      setTimeout(function() {
        get_compliance_export_task(taskId)
      }, 5000);
    } else {
      console.log(jsonObj.status)
    }
  } catch (e) {
    console.log(e)
  }
}


const fs    = require('fs')
const https = require('https')
const url = require('url')
const path = require('path')
/*
* Download the task compressed file and save to a local storage.
*/
async function get_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("Save atttachment 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()
}
import os, time
import requests
from ringcentral import SDK
from ringcentral.http.api_exception import ApiException

#
# Create a task to export the Team Messaging store for a period of time.
#
def create_compliance_export_task():
    print("Create export task.")
    try:
        bodyParams = {
        'timeFrom': "2023-01-01T00:00:00.000Z",
        'timeTo': "2023-01-31T23:59:59.999Z"
        }
        endpoint = "/team-messaging/v1/data-export"
        resp = platform.post(endpoint, bodyParams)
        jsonObj = resp.json()
        get_compliance_export_task(jsonObj.id)
    except ApiException as e:
        print (e)
#
# Check the status of the task using the taskId.
#
def get_compliance_export_task(taskId):
    print("Check export task status ...")
    try:
        endpoint = "/team-messaging/v1/data-export/" + taskId
        resp = platform.get(endpoint)
        jsonObj = resp.json()
        if jsonObj.status == "Completed":
            length = len(jsonObj.datasets)
            for i in range(length):
                fileName = "rc-export-reports_" + jsonObj.creationTime + "_" + str(i) + ".zip"
                get_report_archived_content(jsonObj.datasets[i].uri, fileName)
        elif jsonObj.status == "Accepted" or jsonObj.status == "InProgress":
            time.sleep(5)
            get_compliance_export_task(taskId)
        else:
            print (jsonObj.status)
    except ApiException as e:
        print (e)

#
# Download the task compressed file and save to a local storage.
#
def get_report_archived_content(contentUri, fileName):
    print("Save export zip file to the local machine.")
    uri = platform.create_url(contentUri, False, None, True);
    response = requests.get(uri, stream=True)
    file_size = int(response.headers.get("Content-Length", 0))
    with open(fileName,"wb") as output:
        output.write(response.content)
        print ("File has been downloaded successfully and saved in " + fileName)


# Authenticate a user using a personal JWT token
def login():
  try:
    platform.login( jwt= "SANDBOX_JWT" )
    create_compliance_export_task()
  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_compliance_export_task();

/*
* Create a task to export the Team Messaging store for a period of time.
*/
function create_compliance_export_task(){
  global $platform;
  echo ("Create export task.\n");
  try {
    $bodyParams = array(
      'timeFrom' => "2023-01-01T00:00:00.000Z",
      'timeTo' => "2023-01-31T23:59:59.999Z"
    );
    $endpoint = "/team-messaging/v1/data-export";
    $response = $platform->post($endpoint, $bodyParams);
    $jsonObj = $response->json();
    get_compliance_export_task($jsonObj->id);
  }catch(\RingCentral\SDK\Http\ApiException $e) {
    print_r ('Error: ' . $e->getMessage() . PHP_EOL);
  }
}

/*
* Check the status of the task using the taskId.
*/
function get_compliance_export_task($taskId){
  global $platform;
  echo ("Check export task status ...\n");
  $endpoint = "/team-messaging/v1/data-export/" . $taskId;
  try {
    $response = $platform->get($endpoint);
    $jsonObj = $response->json();
    if ($jsonObj->status == "Completed"){
      for ($i=0; $i<count($jsonObj->datasets); $i++){
        $fileName = "rc-export-reports_" . $jsonObj->creationTime . "_" . $i . ".zip";
        get_report_archived_content($jsonObj->datasets[$i]->uri, $fileName);
      }
    }else if ($jsonObj->status == "Accepted" || $jsonObj->status == "InProgress"){
      sleep(5);
      get_compliance_export_task($taskId);
    }else
      print_r ($jsonObj->status);
  }catch(\RingCentral\SDK\Http\ApiException $e) {
    print_r ('Error: ' . $e->getMessage() . PHP_EOL);
  }
}

/*
* Download the task compressed file and save to a local storage.
*/
function get_report_archived_content($contentUri, $fileName){
  global $platform;
  echo ("Save export zip file to the local machine.\n");
  $uri = $platform->createUrl($contentUri, array(
    'addServer' => false,
    'addMethod' => 'GET',
    'addToken'  => true
  ));
  file_put_contents($fileName, fopen($uri, 'r'));
}
#
# Create a task to export the Team Messaging store for a period of time.
#
def create_compliance_export_task()
    puts "Create export task."
    bodyParams = {
        'timeFrom': "2023-01-01T00:00:00.000Z",
        'timeTo': "2023-01-31T23:59:59.999Z"
      }
    endpoint = "/team-messaging/v1/data-export"
    response = $platform.post(endpoint, payload: bodyParams)
    get_compliance_export_task(response.body['id'])
end

#
# Check the status of the task using the taskId.
#
def get_compliance_export_task(taskId)
    puts "Check export task status ..."
    endpoint = "/team-messaging/v1/data-export/" + taskId
    response = $platform.get(endpoint)
    body = response.body
    if body['status'] == "Completed"
      length = body['datasets'].length
      for i in (0...length)
        fileName = "rc-export-reports_" + body['creationTime'] + "_" + i.to_s + ".zip"
        get_report_archived_content(body['datasets'][i]['uri'], fileName)
      end
    elsif body['status'] == "Accepted" || body['status'] == "InProgress"
      sleep(5)
      get_compliance_export_task(taskId)
    else
         puts body['status']
    end
end

#
# Download the task compressed file and save to a local storage.
#
def get_report_archived_content(contentUri, fileName)
    puts "Save report zip file to the local machine."
    uri = contentUri + "?access_token=" + $platform.token['access_token']
    IO.copy_stream(URI.open(uri), fileName)
end

# Authenticate a user using a personal JWT token
def login():
  begin
    $platform.authorize(jwt: "SANDBOX_JWT")
    create_compliance_export_task()
  rescue StandardError => e
    puts e
  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_Compliance_Data
{
  class Program
  {
    static RestClient restClient;
    static async Task 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_compliance_export_task();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
    /*
    * Create a task to export the Team Messaging store for a period of time.
    */
    static private async Task create_compliance_export_task()
    {
        var bodyParams = new CreateDataExportTaskRequest();
        bodyParams.timeFrom = "2023-01-01T00:00:00.000Z";
        bodyParams.timeTo = "2023-01-31T23:59:59.999Z";

        var resp = await restClient.TeamMessaging().V1().DataExport().Post(bodyParams);
        Console.WriteLine("Create export task");
        var taskId = resp.id;
        Boolean polling = true;
        while (polling)
        {
            Console.WriteLine("Check export task status ...");
            try
            {
                Thread.Sleep(5000);
                // Check the status of the task using the taskId.
                resp = await restClient.TeamMessaging().V1().DataExport(taskId).Get();
                if (resp.status != "InProgress" ||  resp.status != "Accepted")
                {
                    polling = false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
        if (resp.status == "Completed")
        {
            /*
            * Download the task compressed file and save to a local storage.
            */
            for (var i = 0; i < resp.datasets.Length; i++)
            {
                var fileName = "glip-export-reports_" + resp.creationTime + "_" + i + ".zip";
                var contentUrl = resp.datasets[i].uri + "?access_token=" + restClient.token.access_token;
                WebClient webClient = new WebClient();
                webClient.DownloadFile(contentUrl, fileName);
                Console.WriteLine("Save report zip file to the local machine.");
            }
        }
    }
  }
}
package ComplianceExport;

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

import com.ringcentral.*;
import com.ringcentral.definitions.*;

public class ComplianceExport {
    static RestClient restClient;

    public static void main(String[] args) {
        var obj = new ComplianceExport();
        try {
          // Instantiate the SDK
          restClient = new RestClient("SANDBOX-APP-CLIENT-ID", "SANDBOX-APP-CLIENT-SECRET", "https://platform.devtest.ringcentral.com");

          // Authenticate a user using a personal JWT token
          restClient.authorize("SANDBOX-JWT");
          obj.create_compliance_export_task();
        } catch (RestException e) {
          System.out.println(e.getMessage());
        } catch (IOException e) {
          e.printStackTrace();
        }
    }
    /*
    * Create a task to export the Team Messaging store for a period of time.
    */
    public void create_compliance_export_task() throws RestException, IOException {
        var bodyParams = new CreateDataExportTaskRequest();
        bodyParams.timeFrom = "2023-01-01T00:00:00.000Z";
        bodyParams.timeTo = "2023-01-31T23:59:59.999Z";

        var resp = restClient.teamMessaging().v1().dataExport().post(bodyParams);
        System.out.println("Create export task");

        var taskId = resp.id;
        boolean polling = true;
        while (polling)
        {
            System.out.println("Check export task status ...");
            try {
              Thread.sleep(5000);
              resp = restClient.teamMessaging().v1().dataExport(taskId).get();
              if (!resp.status.equals("InProgress") || !resp.status.equals("Accepted"))
                polling = false;
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
        }
        if (resp.status.equals("Completed")) {
            /*
            * Download the task compressed file and save to a local storage.
            */
            for (var i = 0; i < resp.datasets.length; i++) {
              var fileName = "./src/test/resources/glip-export-reports_" + resp.creationTime + "_" + i + ".zip";
              var contentUrl = resp.datasets[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("Save report zip file to the local machine.");
              } catch (IOException e) {
                // handles IO exceptions
                System.out.println("Error!");
              }
            }
        }
    }
}