Skip to main content
Question

How to Determine Whether a Call Has Fully Ended Using the List Company Call Records API

  • June 23, 2026
  • 3 replies
  • 115 views

We are using the List Company Call Records API to retrieve call logs and store the logs in our own database. But we are not able to determine whether a call has fully ended or not, so we can store only those logs which has full call legs.

Is there a specific field in the call log response that reliably indicates that a call has been ended completely or is there any recommended approach to find this out?

3 replies

PhongVu
Community Manager
Forum|alt.badge.img
  • Community Manager
  • June 23, 2026

The call log API returns only completed call records. If you call the API too close to the current time (set by the dateFrom and dateTo params), you may miss those active calls which are in progress (if any), unless you call the API again with overlap dateFrom and dateTo time range. This is because the “dateFrom” and “dateTo” are the call start time, not the end time.

You can use the extract sync API instead, the API also returns only completed call records, but it keep track of the active calls and will return those in the next sync.


 ​@PhongVu 

Thank you for your reply.

For now we've stuck with the List Company Call Records API and handle completeness like this:

  • We poll once a minute with overlapping dateFrom(1 hour from now)/dateTo(current timestamp) windows, and keep each call "pending" until its record shows up, so we don't miss in-progress calls but the API seems to show ongoing call logs as well and there is no way to verify the call has ended or not.
  • So to tackle this, before storing, we confirm the call has actually ended by cross-checking List Company Active Calls — if the telephonySessionId is still there with result: "In Progress", we skip it.
  • Once it's no longer active (that is the result is no longer “In Progress”), we wait for a short cooling period for 40 seconds until the call log record's lastModifiedTime stops changing, since RingCentral appends the final legs/duration/recording shortly after the call ends. Only then do we save it.

- Could you please confirm if this approach is feasible to use?

- Also, we are currently assuming that result: "In Progress" from the Active Calls API indicates that a call has not yet ended. Are there any other possible result values, besides "In Progress", that also represent a call that is still active and has not been completed?


PhongVu
Community Manager
Forum|alt.badge.img
  • Community Manager
  • June 25, 2026

Your approach would work. But it is not optimized as you call the API with overlapping time, which would return redundant call records you have read and processed from the previous API calls. Also, you may miss any call that lasts more than 1 hour, unless you use the call record Ids of those active calls from the active calls list check if the active call is completed and read the call record separately.

I would recommend to use the extract sync API and here is the sample code in Node JS. I would recommend to set the FSync period to 5 mins as near real time. For testing, I set it to 2 mins (MAX_CYCLE = 120). So, change the value accordingly.

const RingCentral = require('@ringcentral/sdk').SDK

RINGCENTRAL_CLIENTID = "";
RINGCENTRAL_CLIENTSECRET = "";
RINGCENTRAL_SERVER = 'https://platform.ringcentral.com'
RC_JWT = ""

const rcsdk = new RingCentral({
server: RINGCENTRAL_SERVER,
clientId: RINGCENTRAL_CLIENTID,
clientSecret: RINGCENTRAL_CLIENTSECRET
})

var platform = rcsdk.platform();

var view = "Detailed"
const RECORDCOUNT = 500
var dateFrom = 0

const MAX_CYCLE = 120
var TIMER = MAX_CYCLE
var timerHandler = undefined
var i = 0
var records = 0

platform.on(platform.events.loginSuccess, async function(e){
console.log("Login success")
var queryParams = {
dateFrom: "2026-04-25T00:00:00.001Z",
syncType: 'FSync',
recordCount: RECORDCOUNT,
view: view
}
await new_sync_account_calllog(queryParams)
});

platform.login({ jwt: RC_JWT })

async function new_sync_account_calllog(params){
console.log("===== new_sync_account_calllog ======")
var endpoint = '/restapi/v1.0/account/~/call-log-extract-sync'
try{
const resp = await platform.get(endpoint, params)
var jsonObj = await resp.json()
if (dateFrom == 0){
dateFrom = new Date().getTime() + 1
console.log("Next FSync dateFrom:", new Date(dateFrom).toISOString())
}

for (var record of jsonObj.records){
console.log(JSON.stringify(record))
console.log("startTime", record.startTime)
console.log("======= **** ========")
}
i++
records += jsonObj.records.length
console.log(`Total: ${records} / This read: ${jsonObj.records.length} / Iterate: ${i}`)
console.log("=====")
console.log(jsonObj.syncInfo)
if (jsonObj.records.length == RECORDCOUNT){
console.log("Read next page using the sync token after 6 secs.")
var params = {
syncToken: jsonObj.syncInfo.syncToken,
syncType: 'ISync',
view: view
}
setTimeout(function(params){
new_sync_account_calllog(params)
}, 6000, params)

}else{
if (timerHandler)
clearInterval(timerHandler)
timerHandler = setInterval(function(){
TIMER--
if (TIMER <= 0){
TIMER = MAX_CYCLE
var from = new Date(dateFrom)
var params = {
dateFrom: from.toISOString(),
syncType: 'FSync',
recordCount: RECORDCOUNT,
view: view
}
dateFrom = 0
new_sync_account_calllog(params)
}else
if (TIMER < 10)
console.log("Time left", TIMER, " secs")
else if (TIMER == 120 || TIMER == 60 || TIMER == 30)
console.log("Time left", TIMER, " secs")
}, 1000)
console.log(`Read ${records} records. Sync again after ${MAX_CYCLE} secs!`)
}
}catch (e){
console.log(e.message)
}
}