Skip to main content

Filtering Faxes by Number, Status, and Date

What are we going to do?

This code snippet shows you how to filter faxes by Number, Status, and Date. We'll be using our Compatibility API List all Faxes endpoint exclusively.

Full code example: List Faxes Filtered by Number and Status
from signalwire.rest import Client as signalwire_client
import pandas as pd
from datetime import datetime

# TODO: Update these variables with your own
space_url = 'YOURSPACENAME.signalwire.com'
project_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
auth_token = 'PTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

client = signalwire_client(
project_id,
auth_token,
signalwire_space_url = space_url)

# TODO: Pick the start and end date. The format must be YYYY/MM/DD
start_date = "2022/04/03"
end_date = "2022/04/04"

# TODO: Numbers to check for under both FROM and TO attributes
# The format needs to be E.164: +12345678901
numbers = [
"+###########",
"+###########",
"+###########",
"+###########",
"+###########"]

# TODO: Add/remove statuses from this list depending on which logs you're looking for
# List of statuses to get the Fax SID for (useful in case you need to contact support)
# These will be the only statuses exported to the faxes.csv
# AVAILABLE STATUSES: 'queued', 'processing', 'sending', 'delivered', 'no-answer', 'busy', 'failed', 'canceled', 'received', 'receiving'
statuses_with_detail = ['failed', 'canceled']

# Faxes we'll need to give more information on and export to CSV
faxes_with_detail = []
# Statuses of faxes where "FROM" matches any of the numbers in the 'numbers' list
from_statuses = []
# Statuses of faxes where "TO" matches any of the numbers in the 'numbers' list
to_statuses = []

# Statistics to be printed in the end
stats = pd.DataFrame(
columns = (
'Queued',
'Processing',
'Sending',
'Delivered',
'No answer',
'Busy',
'Failed OUT',
'Canceled',
'Received',
'Receiving',
'Failed IN'),
index = numbers)

# Statistics formatting options
pd.set_option('display.colheader_justify', 'center')
pd.set_option('display.max_rows', 1000)

for current_number in numbers:
start_datetime = datetime.strptime(start_date, '%Y/%m/%d')
end_datetime = datetime.strptime(end_date, '%Y/%m/%d')

# Listing all faxes FROM every number listed
from_faxes = client.fax.faxes.list(
from_ = current_number,
date_created_after = start_datetime,
date_created_on_or_before = end_datetime)

# Listing all faxes TO every number listed
to_faxes = client.fax.faxes.list(
to = current_number,
date_created_after = start_datetime,
date_created_on_or_before = end_datetime)

# Handle faxes where there is a FROM match
for record in from_faxes:
from_statuses.append((record.status))
the_status = record.status

if the_status in statuses_with_detail:
faxes_with_detail.append((record.from_, record.to, record.status, record.sid))

# Handle faxes where there is a TO match
for record in to_faxes:
to_statuses.append((record.status))
the_status = record.status

if the_status in statuses_with_detail:
faxes_with_detail.append((record.from_, record.to, record.status, record.sid))

# Append this number's statistics
stats.loc[current_number,:] = [
from_statuses.count("queued"),
from_statuses.count("processing"),
from_statuses.count("sending"),
from_statuses.count("delivered"),
from_statuses.count("no-answer"),
from_statuses.count("busy"),
from_statuses.count("failed"),
from_statuses.count("canceled"),
to_statuses.count("received"),
to_statuses.count("receiving"),
to_statuses.count("failed")]

from_statuses = []
to_statuses = []

df = pd.DataFrame(
faxes_with_detail,
columns=(
'From Number',
'To Number',
'Status',
'Fax SID'))

print(df)
print("\n")
print(stats)

df.to_csv(
'faxes.csv',
index = False,
encoding = 'utf-8')

Why use this snippet?

Since faxes can be unreliable, it is crucial to be able to see our success rate at a glace. This code snippet allows us to do precisely this and get the following output:

A table organizing faxes by important information including From and To numbers, Status, and Fax SID. Another table showing detailed status information is also shown.

This is the output you can expect to see in your terminal when you run the code.

Code Walk-through

What we need to run the code

In order to run this code we're going to need to have the following installed (click on top of them to get instructions on how to install them):

What we will need to change

We're going to need to change the following:

  • space_url- Your space URL is the domain of your space, i.e. example.signalwire.com. This can also be found in an easily copyable format within the API tab in your SignalWire Space;
  • project_id- Your project ID is an alphanumeric string that tells the SignalWire SDK where to find your project. You can find this in an easily copyable format by going to your SignalWire Portal and clicking the API tab on the lefthand side;
  • auth_token- Your Auth Token is an alphanumeric string that helps to authenticate your HTTP requests to SignalWire. You can create this (if you haven’t already) or copy this in an easily copyable format by going to your SignalWire Portal and clicking the API tab. If you have not created an API token, press the blue new button. If you have, click show and copy the string;
  • start_date- This is the date from which we wish to look for faxes;
  • end_date- This is the date until which we wish to look for faxes;
  • numbers- This list should contain all of the numbers we wish to look for, in E.164 format;
  • statuses_with_detail- This list should contain all of the statuses we wish to get more information on.
Fax Statuses

Inbound: Received, Receiving, and Failed.
Outbound: Queued, Processing, Sending, Delivered, No answer, Busy, Failed, and Canceled.

from signalwire.rest import Client as signalwire_client
import pandas as pd
from datetime import datetime

# TODO: Update these variables with your own
space_url = 'YOURSPACENAME.signalwire.com'
project_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
auth_token = 'PTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

client = signalwire_client(
project_id,
auth_token,
signalwire_space_url = space_url)

# TODO: Pick the start and end date. The format must be YYYY/MM/DD
start_date = "2022/04/03"
end_date = "2022/04/04"

# TODO: Numbers to check for under both FROM and TO attributes
# The format needs to be E.164: +12345678901
numbers = [
"+###########",
"+###########",
"+###########",
"+###########",
"+###########"]

# TODO: Add/remove statuses from this list depending on which logs you're looking for
# List of statuses to get the Fax SID for (useful in case you need to contact support)
# These will be the only statuses exported to the faxes.csv
# AVAILABLE STATUSES: 'queued', 'processing', 'sending', 'delivered', 'no-answer', 'busy', 'failed', 'canceled', 'received', 'receiving'
statuses_with_detail = ['failed', 'canceled']

Data structure preparation

Here we create the necessary working lists to which we will be adding data as we iterate through the fax records.
We also create the stats DataFrame. It is used solely for general stats per number and per status (regardless of the statuses we picked to get more detail on).
Lastly, we set some Pandas formatting options that are only used in when printing to the terminal. Their purpose is to center the output for an easier time reading it and for it not to summarize the output until we get to 1000 rows.

# Faxes we'll need to give more information on and export to CSV
faxes_with_detail = []
# Statuses of faxes where "FROM" matches any of the numbers in the 'numbers' list
from_statuses = []
# Statuses of faxes where "TO" matches any of the numbers in the 'numbers' list
to_statuses = []

# Statistics to be printed in the end
stats = pd.DataFrame(
columns = (
'Queued',
'Processing',
'Sending',
'Delivered',
'No answer',
'Busy',
'Failed OUT',
'Canceled',
'Received',
'Receiving',
'Failed IN'),
index = numbers)

# Statistics formatting options
pd.set_option('display.colheader_justify', 'center')
pd.set_option('display.max_rows', 1000)

Retrieving and processing the fax data

This is the most important part of the code, as it iterates through the selected list of numbers and carries on the following actions:

  1. Get all faxes between the start and end dates, where the FROM number is the number we're currently looking at;
  2. Get all faxes between the start and end dates, where the TO number is the number we're currently looking at;
  3. Go through each of the faxes where the FROM number matches, and add the status to the from_statuses list. If the status is one of the ones we specified in statuses_with_detail, add the fax information to faxes_with_detail to be printed to the terminal and exported to CSV later on;
  4. Go through each of the faxes where the TO number matches, and add the status to the to_statuses list. If the status is one of the ones we specified in statuses_with_detail, add the fax information to faxes_with_detail to be printed to the terminal and exported to CSV later on;
  5. Add counts of all fax status for this particular number to the stats DataFrame, to then be printed in table format.
for current_number in numbers:
start_datetime = datetime.strptime(start_date, '%Y/%m/%d')
end_datetime = datetime.strptime(end_date, '%Y/%m/%d')

# Listing all faxes FROM every number listed
from_faxes = client.fax.faxes.list(
from_ = current_number,
date_created_after = start_datetime,
date_created_on_or_before = end_datetime)

# Listing all faxes TO every number listed
to_faxes = client.fax.faxes.list(
to = current_number,
date_created_after = start_datetime,
date_created_on_or_before = end_datetime)

# Handle faxes where there is a FROM match
for record in from_faxes:
from_statuses.append((record.status))
the_status = record.status

if the_status in statuses_with_detail:
faxes_with_detail.append((record.from_, record.to, record.status, record.sid))

# Handle faxes where there is a TO match
for record in to_faxes:
to_statuses.append((record.status))
the_status = record.status

if the_status in statuses_with_detail:
faxes_with_detail.append((record.from_, record.to, record.status, record.sid))

# Append this number's statistics
stats.loc[current_number,:] = [
from_statuses.count("queued"),
from_statuses.count("processing"),
from_statuses.count("sending"),
from_statuses.count("delivered"),
from_statuses.count("no-answer"),
from_statuses.count("busy"),
from_statuses.count("failed"),
from_statuses.count("canceled"),
to_statuses.count("received"),
to_statuses.count("receiving"),
to_statuses.count("failed")]

from_statuses = []
to_statuses = []

Printing the results

We prepare the printing of results by creating a DataFrame from the faxes_with_detail list, that contains all of our faxes with statuses specified in the statuses_with_detail list.

The DataFrame resulting from faxes_with_detail is printed to the terminal and exported to a CSV file called faxes.csv.
The stats DataFrame (that gives us general stats on all faxes for the numbers we are looking for) is just printed in the terminal, but could also be exported to CSV if intended.

df = pd.DataFrame(
faxes_with_detail,
columns=(
'From Number',
'To Number',
'Status',
'Fax SID'))

print(df)
print("\n")
print(stats)

df.to_csv(
'faxes.csv',
index = False,
encoding = 'utf-8')

Conclusion

Faxes can be unpredictable due to how old the technology is, but with SignalWire you can make using Fax less of a headache. Just in case something does go wrong, this code snippet should help you gather more information on the problematic faxes, and with the Fax SID our Support team will be able to assist you in getting to the bottom of any issues you're running into!