Call Detail Record Application
If you make calls using CarrierX and want to have a detailed information about these calls for a certain period of time, you can retrieve such information with the help of CarrierX API. But, if you have numerous calls, the call detail records that you receive from the API might contain a lot of data about hundreds or even thousands of calls.
In this case, it might be more useful to get the call detail records one by one, starting with the call made on a certain date and ending with the last call record present in the database.
In this guide, you will learn how to write an application allowing you to request the call detail records starting with a certain date.
I. Plan Application Structure
Before we start writing our application, we need to plan how the application is going to behave depending on different responses from CarrierX API. To do that, we suggest the following algorithm that describes the application behavior:
- The application sends an API request to get the first call made on a certain date, specified in the request.
- CarrierX API responds to the request:
- If the response does not contain any call detail records, the application prints a message and exits.
- If the response contains a call detail record, the application extracts the call detail record secure ID (together with any other data we need).
- Now, the application uses the received secure ID to send a new request that is going to return the call detail record inserted into the database after the record with the secure ID specified in the request.
- If the response does not contain any call detail records, the application considers that the previous record was the last one. It prints a dedicated message and exits.
- If the response contains a call detail record, the application extracts the call detail record secure ID and other required data, and repeats step 3.
This application algorithm can be described with the following block diagram:
II. Form API Requests
- Register with CarrierX to access the CarrierX portal.
- Get authentication token to be able to send the requests and receive responses using CarrierX API.
- Rent a phone number from CarrierX to associate it with the created FlexML endpoint later.
- Make or receive at least a couple of calls using this rented phone number.
Now, we need to understand which API requests we will use to achieve our goal.
1. Get First Call
All the details about the calls are stored in Call Detail Record objects. You can get the information about these records using the following GET
method:
curl -X GET \
'https://api.carrierx.com/core/v2/calls/call_drs' \
-H 'Authorization: Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'
This request will return the list of all the calls made by the partner. If the list is long (in some cases, the lists can include hundreds or even thousands of records) it will take rather a long time and return a lot of information.
To limit the data returned by the request, we will use the following restrictions:
-
apply pagination which includes the use of two parameters
limit
—we set this parameter to1
to limit the number of records in the response as we need only one record;order
—we set this parameter todate_stop+asc
to make sure that the records are properly sorted ascending by thedate_stop
field (i.e., by the date the call ended) and the response returns the call detail record that ended first on the date we set with the filter below.
-
apply result filtering which filters out the irrelevant results. We set it to some date we need (e.g., July 1, 2021) and we will look for the calls which were made either on this date, or later than this date. The
filter
value will be equal todate_stop+ge+2021-07-01
, meaning that we are looking for the date which is greater or equal to July 1, 2021.
Now, our request looks like this:
curl -X GET \
'https://api.carrierx.com/core/v2/calls/call_drs?limit=1&order=date_stop+asc&filter=date_stop+ge+2021-07-01' \
-H 'Authorization: Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'
If the request is successful and there are call detail records matching the restrictions set in the request, the response will look like this:
{
"count": 1,
"has_more": true,
"items": [
{
"cic": null,
"cic_original": null,
"cic_transformed": null,
"date_insert": "2021-07-12T12:24:02.070Z",
"date_start": "2021-07-12T12:21:15.936Z",
"date_stop": "2021-07-12T12:21:45.689Z",
"date_talk": "2021-07-12T12:21:20.347Z",
"direction": "inbound",
"disconnect_originator": "SRC",
"diversion_dst": null,
"diversion_src": null,
"dr_sid": "bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76",
"duration": "29.75362",
"duration_billing": "60",
"endpoint_sid_dst": "4bb610b4-0e76-4d78-b817-7b23673b221b",
"endpoint_sid_src": "db58a951-6146-4941-b936-2ba801dcc5d6",
"identity": null,
"ip_dst": "10.222.2.132:5060",
"ip_src": "12.7.192.27",
"number_billing": "15162065919",
"number_dst": "15162065919",
"number_dst_original": null,
"number_dst_transformed": null,
"number_external": "15187147330",
"number_src": "+15187147330",
"number_src_original": null,
"number_src_transformed": null,
"partner_sid": "cee93bf3-5746-43fe-a1a2-822c05fef687",
"price": "0.0025",
"price_lcr_dst": "0.0025",
"price_lcr_src": null,
"rate": "0.0025",
"rate_lcr_dst": "0.005",
"rate_lcr_src": null,
"sipcallid_dst": "0afd5438792794ef3abb38b432d55a9d@12.7.193.174",
"sipcallid_src": "1d60ac9c16a61ea62f7306851209b393@12.7.192.27",with
"trunk_group_sid_dst": "9dd2f46c-a39e-4a78-82af-cccbd4049ebb",
"trunk_group_sid_src": null,
"trunk_sid_dst": "998ed21f-edec-45f2-9b00-5273620e5c51",
"trunk_sid_src": null,
"type": "telecom",
"version": 2
}
],
"limit": 1,
"offset": 0,
"pagination": {
"next": "https://api.carrierx.com/core/v2/calls/call_drs?limit=1&order=date_stop+asc&filter=date_stop+ge+2021-07-01&offset=1"
},
"total": null
}
If no records matching the restrictions are present in the database, the response will look like this instead:
{
"count": 0,
"has_more": false,
"items": [],
"limit": 1,
"offset": 0,
"pagination": {},
"total": null
}
Change the date and send the request again until you get non-empty results.
2. Get Next Calls
What we need in the response is the items
array which contains the list of the call detail records. We have restricted this list to only one entry and we need the dr_sid
of that single call detail record. In our case, it is "dr_sid": "bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76"
.
Knowing this call detail record secure ID, we can send our next request to get the calls that were inserted into the database after this call.
We will use the pagination in our new request with the same values for the limit
and order
parameters as we did in the previous request.
We will additionally use a new after
query parameter and set it equal to the dr_sid
value from the response:
curl -X GET \
'https://api.carrierx.com/core/v2/calls/call_drs?limit=1&order=date_stop+asc&after=bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76' \
-H 'Authorization: Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'
The successful request will return the list of the call detail records with a single entry of the call following the one with the secure ID specified in the request. An empty list in the response will tell us that the call from the request was the last one made.
Knowing all this, we can proceed to writing the application.
III. Write Application
- Have Python installed on your local machine. There are Python versions available for MS Windows, Mac OS X, various Linux distributions, and some other platforms.
In this section, we will write our application using Python programming language.
1. Send First Request and Get Response
Let’s start with creating a Python code file. We will call it cdr-application.py
.
The only Python library we need to import is Requests. It will allow our application to send the requests to CarrierX API and receive the responses from it:
import requests
Now, let’s add the prerequisites for the first request: the authentication header, the URL to which we will send the request, and the query parameters which must be present in the URL. The GET
request we need is the requests.get()
:
import requests
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': 'date_stop ge 2021-07-01'
}
r = requests.get(url, headers=headers, params=params)
The successful request will return an object that we need to parse in order to get the necessary data (in our case, the call detail record secure ID).
2. Parse Response
As we could see in this section, the response contains the call detail records. They are listed in the items
array.
To get the necessary key from the Call Detail Record object—that is, dr_sid
—we need to get the items
array and parse its first element.
We will save the result from the Python builtin JSON decoder (.json()
) into the dr_items
dictionary variable:
import requests
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': 'date_stop ge 2021-07-01'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
The first element of the dr_items
dictionary will contain the dr_sid
we need.
Now let’s run the application using the following command:
python3 ./cdr-application.py
If the application request is successful, the application will print the following result into the console:
bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76
This is the secure ID of the first call detail record we need.
3. Send Next Requests
Now that we have the secure ID of the first record, we can continue with the requests for the records which follow it.
To do this, we create a second request. We use the same syntax, the only difference is in the request query parameters which contain the after
query parameter instead of the filter:
import requests
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': 'date_stop ge 2021-07-01'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
params = {
'limit': '1',
'order': 'date_stop asc',
'after': dr_sid
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
The successful application requests will print two calls secure IDs, like this:
bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76
012e1d6a-75ac-43ec-bacc-68f1ef1c60a3
4. Poll until Last Record
Great! We see that our application can send the requests we need and returns relevant data. Now we need to poll the call detail records until the API returns no new entries.
We will do this using the while
Python loop.
It works like this:
- while some of the condition is true, the application repeats the code inside the while loop;
- once the condition is false, we break the loop and finish the code execution.
So, in addition to the while
loop we need the condition. In our case, it will be checking if len(r.json()['items'])
is more than 0
. If it is so, then it means that it contains a Call Detail Record object inside it. If it is 0
, it means that this array is empty, i.e., no new calls are available. In this case, we break the loop and the application says No more new calls
:
import requests
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': 'date_stop ge 2021-07-01'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
while True:
params = {
'limit': '1',
'order': 'date_stop asc',
'after': dr_sid
}
r = requests.get(url, headers=headers, params=params)
if len(r.json()['items']):
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
else:
print('No more new calls')
break
Let’s run the application again. If the application requests are successful, it will print the following output into the console:
bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76
012e1d6a-75ac-43ec-bacc-68f1ef1c60a3
56fb6b94-811e-4952-b242-4e06f4e95b7e
No more new calls
5. Add More Checks
But what if the first request returns zero results, meaning that no calls were made since the date in the request? In this case, the application will throw an error.
To avoid such errors, let’s add the code that will check if the first request returns valid results.
We will do it the same way we did with the while
loop—checking the length of the items
array:
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
date = '2021-07-01'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': f'date_stop ge {date}'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
if len(dr_items):
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
else:
print(f'No calls since {date}')
We also moved the date from the first request to the date
variable, and now we can both use it with the request query parameters and display it as a part of the No calls since
message if there are no call detail records for this date.
The application must execute the second and all the following requests only if the first request was also successful. This is why we move our while
loop inside the if
condition of the first request.
The code will look like the following:
import requests
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
date = '2021-07-01'
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': f'date_stop ge {date}'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
if len(dr_items):
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
while True:
params = {
'limit': '1',
'order': 'date_stop asc',
'after': dr_sid
}
r = requests.get(url, headers=headers, params=params)
if len(r.json()['items']):
dr_items = r.json()['items']
dr_sid = dr_items[0]['dr_sid']
print(dr_sid)
else:
print('No more new calls')
break
else:
print(f'No calls since {date}')
If we run our application, it will display the results like at the previous step:
bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76
012e1d6a-75ac-43ec-bacc-68f1ef1c60a3
56fb6b94-811e-4952-b242-4e06f4e95b7e
No more new calls
If we change the date to some later one when there were no calls (e.g., July 15, 2021), the application will print the following text into the console:
No calls since 2021-07-15
6. Save Results to CSV File
Now that the application works as intended, we can save the results into a CSV file.
Python csv library will help us create a CSV file and save the results into it.
The use of the csv
library is not too complicated:
- import the library;
- open the file for writing;
- write the header row;
- write the data rows.
First, we add the csv
library to the existing import
statement like this:
import requests, csv
We create the output CSV file using the with
statement:
with open('calls.csv', 'w', encoding='UTF8') as csv_file:
csv_writer = csv.writer(csv_file)
We will add the following extended information about each call to the the secure IDs of the call detail records: the call date and time, calling party phone number, called party phone number, call direction, duration in seconds, and price in US dollars.
We can take all this information from the Call Detail Record object fields.
The header row will include the names of the attributes. We will create this row like this:
csv_header = ['dr_sid','date_start','number_src','number_dst','direction','duration','price']
csv_writer.writerow(csv_header)
After that we write the data rows. For the first request this will look like this:
csv_row = [dr_items[0]['dr_sid'],dr_items[0]['date_start'],dr_items[0]['number_src'],dr_items[0]['number_dst'],dr_items[0]['direction'],dr_items[0]['duration'],dr_items[0]['price']]
csv_writer.writerow(csv_row)
For the subsequent requests, we first increase the number of records returned in each request. When you have dozens of thousands records in the database, polling one request at a time can take very long time.
We can set a bigger number of the returned records modifying the limit
value.
Let’s set it to 100. In this case, the parameters for the subsequent requests will look like this:
params = {
'limit': '100',
'order': 'date_stop asc',
'after': dr_sid
}
After that, we need to iterate through each of the batch of the records using the for
loop and save the results into our CSV file:
for item in dr_items:
dr_sid = dr_items[len(dr_items) - 1]['dr_sid']
csv_row = [item['dr_sid'],item['date_start'],item['number_src'],item['number_dst'],item['direction'],item['duration'],item['price']]
csv_writer.writerow(csv_row)
We will print the call secure ID with the index to the console. We added the i
variable that will print the number of the record into the console and increment with each new record:
print(f"{i}. {item['dr_sid']}")
The resulting code might look like this:
import requests, csv
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
date = '2021-07-01'
i = 1
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': f'date_stop ge {date}'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
if len(dr_items):
with open('calls.csv', 'w', encoding='UTF8') as csv_file:
csv_writer = csv.writer(csv_file)
csv_header = ['dr_sid','date_start','number_src','number_dst','direction','duration','price']
csv_writer.writerow(csv_header)
dr_sid = dr_items[0]['dr_sid']
csv_row = [dr_items[0]['dr_sid'],dr_items[0]['date_start'],dr_items[0]['number_src'],dr_items[0]['number_dst'],dr_items[0]['direction'],dr_items[0]['duration'],dr_items[0]['price']]
csv_writer.writerow(csv_row)
print(f"{i}. {dr_items[0]['dr_sid']}")
while True:
params = {
'limit': '100',
'order': 'date_stop asc',
'after': dr_sid
}
r = requests.get(url, headers=headers, params=params)
if len(r.json()['items']):
dr_items = r.json()['items']
for item in dr_items:
i += 1
dr_sid = dr_items[len(dr_items) - 1]['dr_sid']
csv_row = [item['dr_sid'],item['date_start'],item['number_src'],item['number_dst'],item['direction'],item['duration'],item['price']]
csv_writer.writerow(csv_row)
print(f"{i}. {item['dr_sid']}")
else:
print('No more new calls')
break
else:
print(f'No calls since {date}')
Now run the resulting application.
If everything is OK, the application will print an output like this into the console:
1. bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76
2. 012e1d6a-75ac-43ec-bacc-68f1ef1c60a3
3. 56fb6b94-811e-4952-b242-4e06f4e95b7e
No more new calls
and create the calls.csv
file which is going to contain the information like this:
dr_sid,date_start,number_src,number_dst,direction,duration,price
bb2aacd2-23d3-418e-9ec0-2fc45c5f9d76,2021-07-12T12:21:15.936Z,+15187147330,15162065919,inbound,29.75362,0.0025
012e1d6a-75ac-43ec-bacc-68f1ef1c60a3,2021-07-12T12:28:30.490Z,+15187147330,15162065919,inbound,46.84222,0.0025
56fb6b94-811e-4952-b242-4e06f4e95b7e,2021-07-14T14:22:36.191Z,+15187147330,15162065515,inbound,37.4222,0.0025
If we change the date to some later one when there were no calls, the application will print the following text into the console, just like it did at step 5:
No calls since 2021-07-15
You can change the data that the application returns or even save all the call detail record fields into the resulting CSV file. To do that, change the code like this:
import requests, csv
headers = {'Authorization': 'Bearer 5ebc03d6-8b2b-44ad-bf65-72d4f1491dda'}
url = 'https://api.carrierx.com/core/v2/calls/call_drs'
date = '2021-07-01'
i = 1
params = {
'limit': '1',
'order': 'date_stop asc',
'filter': f'date_stop ge {date}'
}
r = requests.get(url, headers=headers, params=params)
dr_items = r.json()['items']
if len(dr_items):
with open('calls.csv', 'w', encoding='UTF8') as csv_file:
csv_writer = csv.writer(csv_file)
csv_head = []
for key in dr_items[0]:
csv_head.append(key)
csv_writer.writerow(csv_head)
dr_sid = dr_items[0]['dr_sid']
csv_row_full = []
for key in dr_items[0]:
csv_row_full.append(dr_items[0][key])
csv_writer.writerow(csv_row_full)
print(f"{i}. {dr_items[0]['dr_sid']}")
while True:
params = {
'limit': '100',
'order': 'date_stop asc',
'after': dr_sid
}
r = requests.get(url, headers=headers, params=params)
if len(r.json()['items']):
dr_items = r.json()['items']
for item in dr_items:
i += 1
csv_row_full = []
dr_sid = dr_items[len(dr_items) - 1]['dr_sid']
for key in item:
csv_row_full.append(item[key])
csv_writer.writerow(csv_row_full)
print(f"{i}. {item['dr_sid']}")
else:
print('No more new calls')
break
else:
print(f'No calls since {date}')
This will save all the call detail record names as the CSV header row and their values as data rows.
You can additionally allow the input of the start date when the application starts, or add the date interval (the calls start and end dates) to find all the calls made between certain dates, or change anything in the app to your liking.
IV. Further Reading
You have created an application allowing you to view the detailed information about your calls starting with a certain date!
Refer to the Call Detail Record object API reference to get the complete list of the attributes and methods used with it.