Listing Calls to CSV
These snippets show how you can use SignalWire's API to filter the calls in your project by a number of parameters and then insert the call data into a CSV for your own record keeping.
Full code example: Export Calls to CSV
- Python
- PHP
- Ruby
- Node
- Java
from datetime import datetime
from signalwire.rest import Client as signalwire_client
import pandas as pd
client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'SpaceURL')
calls = client.calls.list(start_time_after=datetime(2021, 0o1, 24, 0, 0, 0), start_time_before=datetime(2021, 0o1, 27, 0, 0, 0), status='completed')
d = []
for record in calls:
d.append((record.from_formatted, record.to_formatted, record.start_time, record.status, record.sid))
print(d)
df = pd.DataFrame(d, columns=('From', 'To', 'Date', 'Status', 'CallSID'))
print('dataframe')
print('\n')
print(df)
df.to_csv('calls.csv', index=False, encoding='utf-8')
<?php
require './vendor/autoload.php';
use SignalWire\Rest\Client;
$client = new Client('ProjectID', 'Auth Token', array("signalwireSpaceUrl" => "YOURSPACE.signalwire.com"));
$calls = $client->calls->read([
"startTimeAfter" => "2021-01-01",
"startTimeBefore" => "2021-02-01",
'Status' => 'busy',
'From' => '+1xxxxxxxxxx',
'To' => '+1xxxxxxxxxx',
]);
$fields = array('Call SID', 'From', 'To', 'Start Time', 'End Time', 'Status', 'Direction', 'Price');
echo '"'.implode('","', $fields).'"'."\n";
$fp = fopen(date("Y-m-d").'_CallReport.csv', 'w');
fputcsv($fp, $fields);
foreach ($calls as $call) {
$row = array(
$call->sid, $call->from, $call->to, $call->startTime->format('Y-m-d H:i:s'), $call->endTime->format('Y-m-d H:i:s'),
$call->status, $call->direction, $call->price,
);
fputcsv($fp, $row);
echo '"'.implode('","', $row).'"'."\n";
}
fclose($fp);
require 'signalwire/sdk'
require 'active_support/time'
require 'csv'
@client = Signalwire::REST::Client.new 'ProjectID', 'Auth Token', signalwire_space_url: 'YOURSPACE.signalwire.com'
calls = @client.calls.list(status: 'completed', end_time_after: (DateTime.now - 7.days).strftime('%a, %d %b %Y %H:%M:%S GMT'))
headers = ['CallSID','Date Created','Direction', 'Duration', 'End Time', 'From', 'To', 'Price']
calls.each do |record|
CSV.open('AccountCalls.csv', 'w+') do |csv|
csv << headers
calls.each do |record|
csv << [record.sid, record.date_created, record.direction, record.duration, record.end_time, record.from,record.to, record.price]
end
end
end
import { RestClient } from "@signalwire/compatibility-api";
import fs from "fs";
const client = RestClient(
"ProjectID",
"Auth Token",
{ signalwireSpaceUrl: "YOURSPACE.signalwire.com" }
);
let writeStream = fs.createWriteStream("CompanyNameCalls.csv");
let newLine = [];
const header = [
"Call Sid",
"To",
"From",
"Start Time",
"End Time",
"Status",
"Direction",
"Duration",
"Price",
];
newLine.push(header);
client.calls
.list({
status: "completed",
startTimeAfter: new Date(Date.UTC(2021, 2, 28, 0, 0, 0)),
})
.then((calls) => {
calls.forEach((c) => {
newLine.push(
c.sid,
c.to,
c.from,
c.startTime,
c.endTime,
c.status,
c.direction,
c.duration,
c.price
);
});
writeStream.write(newLine.join(",") + "\n", () => {});
writeStream.end();
});
import com.google.gson.Gson;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ListCalls {
static String PROJECT_ID = "<ENTER-PROJECT-ID-HERE>";
static String API_TOKEN = "<ENTER-API-TOKEN-HERE>";
static String SPACE_NAME = "<ENTER-SPACENAME-HERE>";
static ArrayList<String[]> dataLines = new ArrayList<>();
static JsonNode loadCalls(String spaceName, String projectId, String apiToken) {
String BASE_URL = String.format("https://%s.signalwire.com/api/laml/2010-04-01/Accounts/%s/Calls", spaceName, projectId);
try {
HttpResponse<JsonNode> response = Unirest.get(BASE_URL)
.basicAuth(projectId, apiToken)
.header("accept", "application/json")
.asJson();
if (response.getStatus() == 200) return response.getBody();
} catch (UnirestException e) {
e.printStackTrace();
return null;
}
return null;
}
public static void main(String[] args){
try {
dataLines.add(new String[]{"From", "To", "Date", "Status", "CallSid"});
Gson gson = new Gson();
JsonNode request = loadCalls(SPACE_NAME, PROJECT_ID, API_TOKEN);
if (request != null){
Results response = gson.fromJson(request.toString(), Results.class);
response.calls.forEach(call -> {
dataLines.add(new String[]{call.from, call.to, call.date_created, call.status, call.sid});
});
createAndPopulateCSV();
}
}catch (Exception exception){
exception.printStackTrace();
}
}
public static String convertToCsv(String[] data) {
return Stream.of(data)
.map(ListCalls::escapeSpecialCharacters)
.collect(Collectors.joining(","));
}
public static void createAndPopulateCSV() throws IOException {
// Auto-generate the name of the file
String filename = "call_result" + System.currentTimeMillis();
// Get the absolute path to the folder you would like to create in the project directory
File file = new File(Paths.get("csv").toAbsolutePath().toUri());
// if file doesn't exist. create a new folder
if (!file.exists()) {
boolean isFolder = file.mkdir();
if (isFolder) {
System.out.println("New folder created!");
} else {
System.out.println("Couldn\'t create folder");
}
}
// create new csv file with the autogenerated name
File csvOutputFile = new File(Paths.get("csv").toAbsolutePath() + "\\" + filename);
try (PrintWriter printWriter = new PrintWriter(csvOutputFile)) {
dataLines.stream()
.map(ListCalls::convertToCsv)
.forEach(printWriter::println); // Write item into the CSV file
System.out.println("Write operation done successfully!");
}
}
public static String escapeSpecialCharacters(String data) {
if (data != null){
String escapeData = data.replace("\\R", " ");
if (data.contains(",") || data.contains("\"")) {
data = data.replace("\"", "\"\"");
escapeData = "\"" + data + "\"";
}
return escapeData;
}
return "null column";
}
static class Results {
public String uri;
public String first_page_uri;
public String next_page_uri;
public String previous_page_uri;
public int page;
public int page_size;
public List<Call> calls;
public Results(String uri, String first_page_uri, String next_page_uri, String previous_page_uri, int page, int page_size, List<Call> calls) {
this.uri = uri;
this.first_page_uri = first_page_uri;
this.next_page_uri = next_page_uri;
this.previous_page_uri = previous_page_uri;
this.page = page;
this.page_size = page_size;
this.calls = calls;
}
}
static class Call {
public String account_sid;
public String annotation;
public String answered_by;
public String api_version;
public String caller_name;
public String date_created;
public String date_updated;
public String direction;
public int duration;
public String end_time;
public String forwarded_from;
public String from;
public String formatted_from;
public String parent_call_sid;
public String phone_number_sid;
public double price;
public String price_unit;
public String sid;
public String start_time;
public String status;
public String to;
public String formatted_to;
public String uri;
public Call(String account_sid, String annotation, String answered_by, String api_version, String caller_name, String date_created, String date_updated, String direction, int duration, String end_time, String forwarded_from, String from, String formatted_from, String parent_call_sid, String phone_number_sid, int price, String price_unit, String sid, String start_time, String status, String to, String formatted_to, String uri) {
this.account_sid = account_sid;
this.annotation = annotation;
this.answered_by = answered_by;
this.api_version = api_version;
this.caller_name = caller_name;
this.date_created = date_created;
this.date_updated = date_updated;
this.direction = direction;
this.duration = duration;
this.end_time = end_time;
this.forwarded_from = forwarded_from;
this.from = from;
this.formatted_from = formatted_from;
this.parent_call_sid = parent_call_sid;
this.phone_number_sid = phone_number_sid;
this.price = price;
this.price_unit = price_unit;
this.sid = sid;
this.start_time = start_time;
this.status = status;
this.to = to;
this.formatted_to = formatted_to;
this.uri = uri;
}
}
}
Step by step walkthroughs will be provided in further detail below as the steps and methods vary with each language. The possible parameters that you can filter by are EndTime
, StartTime
, Status
, To
, From
, and ParentCallSid
.
List Calls to CSV in Python
For the following code to work, you will need to have pandas, datetime, and the SignalWire Python SDK installed.
Read about the different ways to install pandas
Read about datetime and how to install using pip
Read about the SignalWire Python SDK and how to install
First, we need to import the necessary resources.
In this example, that is datetime, pandas, and the SignalWire Client. We also need to instantiate the SignalWire client using the project ID, auth token, and Space URL.
from datetime import datetime
from signalwire.rest import Client as signalwire_client
import pandas as pd
client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'SpaceURL')
Next, we need to choose what parameters we'd like to filter by.
In this example, I have included how to filter by a date range and by the status of the call. Start Time is a datetime object where the order for the arguments is Year, Month, Date, Hour, Minute, and Seconds. You can leave hour, minute, and seconds at 0, unless you have a specific time of day you would like to filter by.
For months Jan - September, A slight change was made because python version (3.9) does not support leading 0's in datetime anymore. You must use the 0o prefix for octal literals now. That is reflected below in the code. If your version doesn’t include that limitation, you can switch it back to 01 or whatever month you need.
You can filter by the possible statuses of queued
, ringing
, in-progress
, canceled
, completed
, busy
, failed
.
calls = client.calls.list(start_time_after=datetime(2021, 0o1, 24, 0, 0, 0), start_time_before=datetime(2021, 0o1, 27, 0, 0, 0), status='completed')
We now need to insert the data from calls into an array.
Here we set up an empty array. This will contain all of the data that we will gather from the calls. We can loop through calls and append each of the following parameters to our empty array: form_formatted
, to_formatted
, start_time
, status
, and sid
.
You can expand this to include as many or as few parameters as you'd like. See all of the parameters returned in the JSON response in our API documentation.
After that, we print the array so that we can see what we have inserted for debugging purposes.
d = []
# Appends all data from calls into an array
for record in calls:
d.append((record.from_formatted, record.to_formatted, record.start_time, record.status, record.sid))
print(d)
Next, we create a dataframe and export it to CSV.
The next section of this code is to create a dataframe using pandas with column name headers. It's important to make sure that the order of the headers matches the order of the parameters you inserted into the array above. If you choose to add more or remove parameters, make sure to double check that the order matches or your data will be mismatched in the CSV.
We then print the dataframe for debugging purposes and export the dataframe to csv. Using the parameter index=False turns off the indexing for each row. You can rename calls.csv to be as specific or general as you'd like.
df = pd.DataFrame(d, columns=('From', 'To', 'Date', 'Status', 'CallSID'))
print('dataframe')
print('\n')
print(df)
df.to_csv('calls.csv', index=False, encoding='utf-8')
List Calls to CSV in PHP
For the following code to work, you will need to have the SignalWire PHP SDK installed.
Read about the SignalWire PHP SDK and how to install it.
You will also need to make sure that the vendor/autoload.php path points to the correct location on your computer, as we can’t determine that for you. However, if you want to run this script exactly, install the SDK from within the folder that contains this PHP script.
First, we need to import the necessary resources.
In this example, that just means we need to point to the correct path of the vendor autoload file on your computer. We also need to instantiate the SignalWire client using the project ID, auth token, and Space URL.
<?php
require './vendor/autoload.php';
use SignalWire\Rest\Client;
$client = new Client('ProjectID', 'Auth Token', array("signalwireSpaceUrl" => "YOURSPACE.signalwire.com"));
Next, we need to choose what parameters we'd like to filter by.
In this example, I have included how to filter by a date range, call status, from number, and to number.
$calls = $client->calls->read([
"startTimeAfter" => "2021-01-01",
"startTimeBefore" => "2021-02-01",
'Status' => 'busy',
'From' => '+1xxxxxxxxxx',
'To' => '+1xxxxxxxxxx',
]);
In the next section, we need to create the file to insert the call data into.
Begin by writing headers and storing them in a variable called $fields
. We also use implode
to join the elements of the array with a string. We will then use fopen
to create and open a file named TodaysDate_CallReport. After that, we use fputcsv
to insert our headers stored in $fields
into our file. TodaysDate_CallReport.
$fields = array('Call SID', 'From', 'To', 'Start Time', 'End Time', 'Status', 'Direction', 'Price');
echo '"'.implode('","', $fields).'"'."\n";
$fp = fopen(date("Y-m-d").'_CallReport.csv', 'w');
fputcsv($fp, $fields);
Next, we need to loop through our $calls
array in order to gather the necessary call data and insert it into our CSV.
It is important to make sure the order of the headers is the same as the order of the values we will be gathering. As we loop through each call record, we will insert it into the CSV one by one and use implode to join the elements of the array with a string. The last step is to close the file!
foreach ($calls as $call) {
$row = array(
$call->sid, $call->from, $call->to, $call->startTime->format('Y-m-d H:i:s'), $call->endTime->format('Y-m-d H:i:s'),
$call->status, $call->direction, $call->price,
);
fputcsv($fp, $row);
echo '"'.implode('","', $row).'"'."\n";
}
fclose($fp);
List Calls to CSV in Ruby
For the following code to work, you will need to have Active Support, CSV, and the SignalWire Ruby SDK installed.
Read about the SignalWire Ruby SDK and how to install it.
Read about Active Support and how to install it.
Read about CSV and how to install it.
First, we need to import the necessary resources.
In this case, we need to import signalwire/sdk
, active_support/time
, and csv
.
We also need to instantiate the SignalWire client using the project ID, auth token, and Space URL.
require 'signalwire/sdk'
require 'active_support/time'
require 'csv'
@client = Signalwire::REST::Client.new 'ProjectID', 'Auth Token', signalwire_space_url: 'YOURSPACE.signalwire.com'
Next, we need to choose what parameters we'd like to filter by.
In this example, I have included how to filter by a date range of the last 7 days and a status of completed.
calls = @client.calls.list(status: 'completed', end_time_after: (DateTime.now - 7.days).strftime('%a, %d %b %Y %H:%M:%S GMT'))
Next, we need to create headers for our CSV and insert the headers/call records into the CSV.
It's important to make sure that the headers are in the exact same order as the call record parameters.
In the code section below, we create an array of headers. Next, we open a file AccountCalls.csv. We insert the headers before we begin the loop. Otherwise, the headers will precede every single record. After the headers have been inserted, we loop through each of the call records in calls
and insert them one by one with all the listed parameters into the CSV.
headers = ['CallSID','Date Created','Direction', 'Duration', 'End Time', 'From', 'To', 'Price']
calls.each do |record|
CSV.open('AccountCalls.csv', 'w+') do |csv|
csv << headers
calls.each do |record|
csv << [record.sid, record.date_created, record.direction, record.duration, record.end_time, record.from,record.to, record.price]
end
end
end
List Calls to CSV in Node.js
For the following code to work, you will need to have the SignalWire NodeJS SDK installed.
Read about the SignalWire NodeJS SDK and how to install it.
First, we need to import the necessary resources.
In this case, we need to import @signalwire/compatibility-api
and fs
.
We also need to instantiate the SignalWire client using the project ID, auth token, and Space URL.
import { RestClient } from "@signalwire/compatibility-api";
import fs from "fs";
const client = RestClient(
"ProjectID",
"Auth Token",
{ signalwireSpaceUrl: "YOURSPACE.signalwire.com" }
);
Next, we need to create our CSV file: an empty array to put our records into, and an array of headers.
It's important to make sure that later when we loop through the call record, we push the parameters into the CSV in the same order as the headers here. Lastly, we push the headers into the CSV as the first row.
let writeStream = fs.createWriteStream("CompanyNameCalls.csv");
let newLine = [];
const header = [
"Call Sid",
"To",
"From",
"Start Time",
"End Time",
"Status",
"Direction",
"Duration",
"Price",
];
newLine.push(header);
Next, we determine which parameters we'd like to filter by and what parameters we expect to be pushed into the CSV.
The filters used in this example are status and start time. When using date-time objects in Javascript, it's important to remember that it starts at 0 with 0 being January. Then as we loop through calls
, we push each parameter into the CSV one by one. After we are finished looping through calls
We use writeStream.write
to separate these values by commas and add a new line at the end. Lastly, we use writeStream.end
to close the file.
client.calls
.list({
status: "completed",
startTimeAfter: new Date(Date.UTC(2021, 2, 28, 0, 0, 0)),
})
.then((calls) => {
calls.forEach((c) => {
newLine.push(
c.sid,
c.to,
c.from,
c.startTime,
c.endTime,
c.status,
c.direction,
c.duration,
c.price
);
});
writeStream.write(newLine.join(",") + "\n", () => {});
writeStream.end();
});
List Calls to CSV in Java
For the following code to work, you would need to have the following set up:
- Java Environment
- A maven project
- Gson
- Unirest
First, we need to import the necessary resources.
import com.google.gson.Gson;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ListCalls {
static String PROJECT_ID = "<ENTER-PROJECT-ID-HERE>";
static String API_TOKEN = "<ENTER-API-TOKEN-HERE>";
static String SPACE_NAME = "<ENTER-SPACENAME-HERE>";
static ArrayList<String[]> dataLines = new ArrayList<>();
We will be using the SignalWire Calls endpoint on the Compatibility API to list all the calls made on a SignalWire Space.
We need to create an Helper static
method that would be used to make calls on the endpoint and return a response that contains calls during the requested period. The method loadCalls
takes the parameters spaceName
, projectId
, and apiToken
.
static JsonNode loadCalls(String spaceName, String projectId, String apiToken) {
String BASE_URL = String.format("https://%s.signalwire.com/api/laml/2010-04-01/Accounts/%s/Calls", spaceName, projectId);
try {
HttpResponse<JsonNode> response = Unirest.get(BASE_URL)
.basicAuth(projectId, apiToken)
.header("accept", "application/json")
.asJson();
if (response.getStatus() == 200) return response.getBody();
} catch (UnirestException e) {
e.printStackTrace();
return null;
}
return null;
}
Now we need to set the header of our csv using a List
that takes String[]
value. The variable holding data to be exported to CSV would be called dataLines
. After fetching the calls using the helper method, we would use Gson
to convert the JSON response to a class object Result which you can find inside the full code. Now we can loop through our result and call another helper method createAndPopulateCSV
to populate our response into a CSV.
public static void main(String[] args){
try {
dataLines.add(new String[]{"From", "To", "Date", "Status", "CallSid"});
Gson gson = new Gson();
JsonNode request = loadCalls(SPACE_NAME, PROJECT_ID, API_TOKEN);
if (request != null){
Results response = gson.fromJson(request.toString(), Results.class);
response.calls.forEach(call -> {
dataLines.add(new String[]{call.from, call.to, call.date_created, call.status, call.sid});
});
createAndPopulateCSV();
}
}catch (Exception exception){
exception.printStackTrace();
}
}
Additional Logging
For even more detailed logging, you can modify the examples above to automatically pull the numbers from your desired project and record the call count per number. Your time is important, so here is a prebuilt example using Python!
from datetime import datetime
from signalwire.rest import Client as signalwire_client
import pandas as pd
# TODO: UPDATE WITH YOUR CREDENTIALS
ProjectID = "Project ID Goes Here"
AuthToken = "API Token Goes Here"
SpaceURL = "Your-Space-Name-Goes-Here.signalwire.com"
# TODO: UPDATE WITH DESIRED TIME & DATE
start_date = datetime(2023, 3, 1)
end_date = datetime(2023, 7, 30)
client = signalwire_client(ProjectID, AuthToken, signalwire_space_url=SpaceURL)
call_records = []
call_counts = {}
numbers = [(record.phone_number,) for record in client.incoming_phone_numbers.list()]
# Tracks the amount of numbers pulled for adding progress notifications in the console.
total_numbers = len(numbers)
for progress, number in enumerate(numbers, 1):
# Retrieve completed calls for the current number (incoming and outgoing)
calls_to = client.calls.list(start_time_after=f"{start_date}", start_time_before=f"{end_date}", to=f"{number}",
status='completed')
calls_from = client.calls.list(start_time_after=f"{start_date}", start_time_before=f"{end_date}", from_=f"{number}",
status='completed')
# Update the calls count for each unique phone number.
call_counts[number] = call_counts.get(number, 0) + len(calls_to) + len(calls_from)
# Append the call records.
call_records.extend(
[(record.from_formatted, record.to_formatted, record.start_time, record.status, record.sid, record.price)
for record in calls_to] +
[(record.from_formatted, record.to_formatted, record.start_time, record.status, record.sid, record.price)
for record in calls_from]
)
# Print progress notifications
print(f"Processing {progress}/{total_numbers} phone numbers...")
df = pd.DataFrame(call_records, columns=("From", "To", "Date", "Status", "CallSID", "Price"))
call_counts_df = pd.DataFrame({'Phone Number': list(call_counts.keys()), 'Total Calls': list(call_counts.values())})
# Calculate the total cost of calls
total_cost = df['Price'].sum()
formatted_cost = f"${total_cost:,.2f}"
# Combine the call records and the total call count into a single DataFrame
combined_df = pd.concat([df, call_counts_df], axis=1)
# Save the combined DataFrame to a CSV file
combined_df.to_csv('Call_Logs.csv', index=False, encoding='utf-8')
print(f"\nThe total cost of calls in your selected date range is approximately {formatted_cost} USD."
f" Check the Call_Logs.csv file for additional details!")
Conclusion
Record keeping is important, so we hope these examples help make it easier to filter your calls and export them to an external CSV with ease. All of these examples will accomplish the same goal and can be built upon to expand or further drill down the amount of data returned. Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!