Skip to main content

Listing Price Summaries

Overview

With this code snippet you can get the total cost of messaging in a specific date range.

Full code example: How to Use List Messages API to Get Price Stats
from datetime import datetime
from signalwire.rest import Client as signalwire_client
import pandas as pd

client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url='YourSpace.signalwire.com')

messages = client.messages.list(date_sent_after=datetime(2021, 10, 1), date_sent_before=datetime(2021, 10, 31))


d = []
status = []

for record in messages:
d.append((record.from_, record.to, record.date_sent, record.sid, record.price, record.direction, record.status))
status.append(record.status)

total_sent=int(status.count("sent"))
total_received=int(status.count("received"))
total_delivered=int(status.count("delivered"))
total_undelivered=int(status.count("undelivered"))

num_outbound_messages = total_sent + total_delivered + total_undelivered
num_inbound_messages = total_received

df = pd.DataFrame(d, columns=('From', 'To', 'Date', 'MessageSID', 'Price', 'Message Direction', 'Message Status'))
print(df)
df.to_csv('Messages.csv', index=False, encoding='utf-8')
print()

totalMess = len(df)
totalCost = df['Price'].sum()
formattedCost = "${:,.2f}".format(totalCost)

print("You sent " + str(totalMess) + " total messages during your selected date range.")
print("The total cost of messages in your selected date range is approximately " + formattedCost + " USD.")
print("There were " + str(total_delivered) + " delivered messages and " + str(total_undelivered) + " undelivered messages.")
print("There were " + str(num_inbound_messages) + " inbound messages and " + str(num_outbound_messages) + " outbound messages.")

Python

What do I need to run this code?

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 here.

Read about DateTime and how to install using pip here.

Read about the SignalWire Python SDK and how to install here.

Code Walkthrough

Load the necessary libraries and instantiate the SignalWire Client

We will start by importing 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')

Select time frame to filter by

In this example, I have included how to filter by DateSentAfter and DateSentBefore to return all messages between a specific date range. DateSent is a DateTime object where the order for the arguments is Year, Month, Date, Hour, Minute, Seconds. You can leave hour, minute, and seconds at 0, unless you have a specific time of day you would like to filter by.

messages = client.messages.list(date_sent_after=datetime(2021, 10, 1), date_sent_before=datetime(2021, 10, 31))
Octal Literals in Some Python Versions

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.

Prepare data structures

Next, we will create two arrays: d and status. d will contain all of the message records within the specified date range and status will contain only the message statuses which we will use to get some summarized stats. We will loop through each message record returned by the List Messages API and add additional detail to the row as well as adding the status alone to the status array.

for record in messages:
d.append((record.from_, record.to, record.date_sent, record.sid, record.price, record.direction, record.status))
status.append(record.status)

Prepare status counter variables

Next we will categorize the message status for all our returned messages and count how many are inbound vs outbound.

# categorize message status for all returned messages
total_sent=int(status.count("sent"))
total_received=int(status.count("received"))
total_delivered=int(status.count("delivered"))
total_undelivered=int(status.count("undelivered"))

# count how many are inbound vs outbound
num_outbound_messages = total_sent + total_delivered + total_undelivered
num_inbound_messages = total_received

Now that all of the message data is stored in d, we need to convert it to a data frame to make for easier containment as well as the ability to convert to CSV. It's important to make sure that the column headers are in the same order as the message record details added to d.

# create dataframe and convert to CSV
df = pd.DataFrame(d, columns=('From', 'To', 'Date', 'MessageSID', 'Price', 'Message Direction', 'Message Status'))
print(df)
df.to_csv('Messages.csv', index=False, encoding='utf-8')
print()

As we want to get the amount spent in our date range, we will add up the cost of the Price column in the dataframe and convert the float to a currency format.

totalMess = len(df)
totalCost = df['Price'].sum()
formattedCost = "${:,.2f}".format(totalCost)

Lastly, we will use the data and values that we've calculated to display the total cost as well as some summaries about delivery status and the message type distribution.

print("You sent " + str(totalMess) + " total messages during your selected date range.")
print("The total cost of messages in your selected date range is approximately " + formattedCost + " USD.")
print("There were " + str(total_delivered) + " delivered messages and " + str(total_undelivered) + " undelivered messages.")
print("There were " + str(num_inbound_messages) + " inbound messages and " + str(num_outbound_messages) + " outbound messages.")
A screenshot of the text output. It reads: 'You sent 51 total messages during your selected date range. The total cost of messages in your selected date range is approximately $0.32 USD. There were 34 delivered messages and 16 undelivered messages. There were 0 inbound messages and 51 outbound messages.

Node.js

What do I need to run this code?

We will need the following libraries (click their names to get instructions on how to install them):

How to Run Snippet?

If you save this code snippet in a file called messagingPricingSummaries.js, for example, you then need to run:
node messagingPricingSummaries.js.

Code Walkthrough

Load the necessary libraries

const dfd = require("danfojs");
const fs = require("fs");
const { RestClient } = require("@signalwire/compatibility-api");

Instantiate the SignalWire Rest Client

In order for us to connect to SignalWire later on in the code using the Rest Client we first need to make sure we update space_url, project_id, and access_token.

let space_url = "YOURSPACENAME.signalwire.com";
let project_id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX";
let access_token = "PTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

const client = RestClient(project_id, access_token, { signalwireSpaceUrl: space_url });

Create the necessary variables

Here we create the data array, to which we'll add all message data as it is loaded, as well as variables that will serve as counters for each status.

let data = [];

let total_sent = 0;
let total_received = 0;
let total_delivered = 0;
let total_undelivered = 0;

Get the message data for a given period

In this section of the code we get the message list using client.messages.list(), and passing it the dateSentAfter and dateSentBefore parameters.

Once we get the message list, we then add each message to the data array and increment the status counters depending on the message status.

const getMessageList = client.messages.list({
dateSentAfter: new Date(Date.UTC(2022, 02, 10)),
dateSentBefore: new Date(Date.UTC(2022, 04, 26)),
});

getMessageList.then((messages) => {
messages.forEach(message => {
data.push([
message.from,
message.to,
message.dateSent,
message.sid,
message.price,
message.direction,
message.status
]);

switch (message.status) {
case "sent":
total_sent++;
break;
case "received":
total_received++;
break;
case "delivered":
total_delivered++;
break;
case "undelivered":
total_undelivered++;
break;
}
});

Prepare all data and print the results

Once all messages have been parsed, we are ready to prepare the variables that will help make the final result more readable, such as the number of outbound messages as well as inbound.

We create the all_data DataFrame, that will help up with printing the results to the terminal and to a CSV file.

We also get the total number of messages for this period, and sum up the cost of the traffic.

Finally, we print comprehensible results using the data we have gathered from all of the messages. Utilizing the all_data DataFrame we print a list of all messages from this period to the terminal and to a CSV file named Messages.csv.

let num_outbound_messages = total_sent + total_delivered + total_undelivered;
let num_inbound_messages = total_received;

let all_data = new dfd.DataFrame(data, {
columns: ['From', 'To', 'Date', 'MessageSID', 'Price', 'Message Direction', 'Message Status'],
config: {
tableDisplayConfig: {
columns: [
{ width: 3 },
{ width: 13 },
{ width: 13 },
{ width: 36},
{ width: 36 },
{ width: 13 },
{ width: 12 },
{ width: 16}
],
},
tableMaxRow: 1000
},
});

let totalMessages = data.length;
let totalCost = all_data["Price"].sum().toFixed(2);

console.log("You sent " + totalMessages + " total messages during your selected date range.");
console.log("The total cost of messages in your selected date range is approximately " + totalCost + " USD.");
console.log("There were " + total_delivered + " delivered messages and " + total_undelivered + " undelivered messages.");
console.log("There were " + num_inbound_messages + " inbound messages and " + num_outbound_messages + " outbound messages.");

all_data.print();
fs.writeFileSync("Messages.csv", dfd.toCSV(all_data));
})

PHP

What do I need to run this code?

We will need the following libraries (click their names to get instructions on how to install them):

  • SignalWire Rest Client
  • You will also need to make sure that the vendor/autoload.php path points to the correct location in 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.

How to Run Snippet?

If you save this code snippet in a file called messagingPricingSummaries.php, for example, you then need to run:
php messagingPricingSummaries.php.

Code Walkthrough

Load the necessary libraries

<?php
require __DIR__ .'/vendor/autoload.php';

use SignalWire\Rest\Client;

Instantiate the SignalWire Rest Client

In order for us to connect to SignalWire later on in the code using the Rest Client we first need to make sure we update space_url, project_id, and access_token.

$client = new Client('YOUR-PROJECT-ID', 'YOUR-API-TOKEN', array("signalwireSpaceUrl" => "YOURSPACENAME.signalwire.com"));

Create the necessary variables

Here we create the $header_fields array, to help the output CSV be more readable. We'll also create some variables that will serve as counters for the different statuses, and total messages sent or received, as well as the total price. We also open the output file and write out our header row to it.

// Write Headers for output CSV.
$header_fields = array('From', 'To', 'Date Sent', 'Message SID', 'Price', 'Direction','Status',);
echo '"'.implode('","', $header_fields).'"'."\n";
// Open File named Messages.csv
$fp = fopen('Messages.csv', 'w');
// Insert headers into output Messages.csv file.
fputcsv($fp, $header_fields);
// Define some variables for tracking
$total_cost=0;
$total_sent=0;
$total_rec=0;
$total_delivered=0;
$total_undelivered=0;
$total_messages=0;
$num_outbound_msg=0;
$num_inbound_msg=0;

Get the message data for a given period

In this section of the code we get the message data to calculate usage and pricing using the dateSentAfter and dateSentBefore parameters to establish a window for the results.

Once we get the message data, we then add each message to the $row array and increment the status counters depending on the message status.

// Can filter message by whatever parameters you need. This example is any message sent after January 1, 2022.
$messages = $client->messages->read([
"dateSentAfter" => "2022-01-01",
"dateSentBefore" => "2022-04-29",
]);
// Write rows
foreach ($messages as $message) {
$row = array(
$message->from,
$message->to,
$message->dateSent->format('Y-m-d H:i:s'),
$message->sid,
$message->price,
$message->direction,
$message->status,
);
$total_cost += $message->price;
if ($message->status == "sent") {
$total_sent++;
$total_messages++;
} else if ($message->status == "received") {
$total_rec++;
$total_messages++;
} else if ($message->status == "failed" || $message->status == "undelivered") {
$total_undelivered++;
$total_messages++;
} else if ($message->status == "delivered") {
$total_delivered++;
$total_messages++;
}
// Insert rows into CSV
fputcsv($fp, $row);
echo '"'.implode('","', $row).'"'."\n";
}

Prepare all data and print the results

Once all messages have been parsed, we are ready to prepare the variables that will help make the final result more readable, such as the number of outbound messages as well as inbound.

We push the $row array to our CSV. We also get the total number of messages for this period, and sum up the cost of the traffic, turning it into currency from a float.

Finally, we print results using the data we have gathered from all of the messages to the terminal, showing message counts, and pricing.

$num_outbound_msg=$total_sent+$total_delivered+$total_undelivered;
$num_inbound_msg=$total_rec;

$formatted_cost=new NumberFormatter('en_US',NumberFormatter::CURRENCY);
$formatted_cost->setTextAttribute( $formatted_cost::CURRENCY_CODE, 'USD' );
$formatted_cost->setAttribute( $formatted_cost::FRACTION_DIGITS, 2 );
$numberString = $formatted_cost->format( $total_cost );
print "There were " . $total_messages . " total messages during your selected date range.\n";
print "The total cost of messages in your selected date range is approximately " . $numberString . " USD.\n";
print "There were " . $total_delivered . " delivered messages and " . $total_undelivered . " undelivered messages.\n";
print "There were " . $num_inbound_msg . " inbound messages and " . $num_outbound_msg . " outbound messages.\n";

// close file
fclose($fp);

Java

What do I need to run this code?

For the following code to work, you will need to have a Maven project, The Java Wrapper Library and a Signalwire account.

Read about how to get started with the Java Wrapper API here

Read on how to create a Maven project with Intellij here

** How to get API Credentials **

The API also requires that you authenticate yourself using your Project ID, API Token, and Space URL. If you do not know where to find these values, check out our guide here!

How to Run Snippet?

Assuming you've named your script MessagePriceSummary.java you would need to do the following to run the javac MessagePriceSummary.java then java MessageFromNumber.java.

Code Walkthrough

We also need to instantiate the SignalWire client using the project ID, auth token, and space URL

public static SignalWireClient client() {
return new SignalWireClient("YOUR-PROJECT-ID",
"YOUR-API-TOKEN",
"YOUR-SPACE-NAME");
}

In the main method we need to get our messages the client().message().getMessages().messages method to populate messages from your SignalWire Space.

      List<Message> messages = client().message().getMessages().messages;

Create a variable to store the result of delivered, sent, undelivered, received and initialize all as zero.

        int delivered = 0;
int undelivered = 0;
int sent = 0;
int received = 0;
double price = 0d;

Loop through the result of the messages from the Signalwire API and then append them into the dataLines array that would be used to populate the CSV.

As we loop through each item from the API result, We increment the status variable by 1 if its equal to the matching status in our if statement.

for (Message message : messages) {
dataLines.add(new String[]{message.from, message.to, message.date_created, message.to, message.sid});

if (message.price != null) {
price += Double.parseDouble(message.price);
}
switch (message.status) {
case "sent":
sent += 1;
break;
case "delivered":
delivered += 1;
break;
case "undelivered":
undelivered += 1;
break;
case "received":
received += 1;
break;
default:
System.out.println("Something went wrong");
}
}

Now that we have the values for undelivered, delivered, sent, received we would print it out to the console for display

  String totalMessage = String.format("You sent %d total messages on your space", messages.size());
String priceSummary = String.format("The total cost of messages in your selected date range is approximately %,.2f USD", price);
String messageStatus = String.format("There were %d delivered messages and %d undelivered messages.", delivered, undelivered);
String messageRecipient = String.format("There were %d inbound messages and %d outbound messages.", received, sent);

System.out.println(totalMessage);
System.out.println(priceSummary);
System.out.println(messageStatus);
System.out.println(messageRecipient);

After displaying the summary as show above, we can then call the createAndPopulateCSV() method that then generates the CSV.

 try {
createAndPopulateCSV();
} catch (IOException ioException) {
ioException.printStackTrace();
}

Full java code:

import io.github.olajhidey.SignalWireClient;
import io.github.olajhidey.model.message.Message;

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 MessageSummary {

public static List<String[]> dataLines = new ArrayList<>();

public static SignalWireClient client() {
return new SignalWireClient("YOUR-PROJECT-ID",
"YOUR-API-TOKEN",
"YOUR-SPACE-NAME");
}

public static void main(String[] args) {

List<Message> messages = client().message().getMessages().messages;

int delivered = 0;
int undelivered = 0;
int sent = 0;
int received = 0;
double price = 0d;

dataLines.add(new String[]{"From", "To", "Date", "Status", "MessageSID"});

for (Message message : messages) {
dataLines.add(new String[]{message.from, message.to, message.date_created, message.to, message.sid});

if (message.price != null) {
price += Double.parseDouble(message.price);
}
switch (message.status) {
case "sent":
sent += 1;
break;
case "delivered":
delivered += 1;
break;
case "undelivered":
undelivered += 1;
break;
case "received":
received += 1;
break;
default:
System.out.println("Something went wrong");
}
}

String totalMessage = String.format("You sent %d total messages on your space", messages.size());
String priceSummary = String.format("The total cost of messages in your selected date range is approximately %,.2f USD", price);
String messageStatus = String.format("There were %d delivered messages and %d undelivered messages.", delivered, undelivered);
String messageRecipient = String.format("There were %d inbound messages and %d outbound messages.", received, sent);

System.out.println(totalMessage);
System.out.println(priceSummary);
System.out.println(messageStatus);
System.out.println(messageRecipient);

try {
createAndPopulateCSV();
} catch (IOException ioException) {
ioException.printStackTrace();
}

}

public static String convertToCsv(String[] data) {
return Stream.of(data)
.map(MessagesList::escapeSpecialCharacters)
.collect(Collectors.joining(","));
}

public static void createAndPopulateCSV() throws IOException {

// Auto-generate the name of the file
String filename = "message_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(MessageSummary::convertToCsv)
.forEach(printWriter::println); // Write item into the CSV file
System.out.println("Write operation done successfully!");
}

}

public static String escapeSpecialCharacters(String data) {
String escapeData = data.replace("\\R", " ");
if (data.contains(",") || data.contains("\"")) {
data = data.replace("\"", "\"\"");
escapeData = "\"" + data + "\"";
}
return escapeData;
}


}

Wrap up

Your SignalWire Space allows you to get a good picture of your messaging costs already, but in case you need more information on any given period, these code snippets should help you get all the information you need!

Sign Up Here

If you would like to test this example out, you can create a SignalWire account and space here.

Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!