List all Numbers with Messaging Campaign Assignments to csv

Using SignalWIre's Campaign Registry APIs and SignalWire's Python SDK, this snippet will find all phone number assignments, format a data table, and much, much more!

What are we going to do?

This snippet incorporates SignalWire's Campaign Registry APIs to list all number assignments for your space. You can then build a data frame with any information that you may need for better monitoring of your numbers.

The List Phone Number Assignments API will only retrieve assignments for the project that is entered through the authorization. In order to run this code for all messaging campaigns in our space, we will need to upload the authorization for each project we would like to investigate through a csv file.

In order to create a data table, this application will begin by listing out all brands for your space. Once all brands for your space are listed, the code will dig through each of these brands to find the campaigns that are associated with them. Once all campaigns are listed, the next step is to search through all of these campaigns for their number assignments.

After all of the numbers have been listed, it is fairly simple to fill in the project ID, campaign ID, and the association status of each number listed. Then, the only thing left to do is combine it all into a data table and export it to a csv file.

What you need to run the code

You must have the SignalWire Python SDK installed. You can install that here:

The Python SDK will be used with the assistance of the base64, requests and pandas packages.

Lastly, you will need a csv that lists out each project's 'Project_ID' and 'API_Token'. This csv will be imported in one of the first few lines of the code so make sure to copy the path properly. An example of this csv file can be found below.

Project_ID,API_Token
d6hc46uf-pp09-fy82-84ft-XXXXXXXXXXXX,PT8jj31b6art535085XXXXXXXXXXXXXXXXXXXXX
vnjow029-p149-gy82-09ft-XXXXXXXXXXXX,PTgk991b6art535085XXXXXXXXXXXXXXXXXXXXX
09entoe5-pt69-fy82-84ft-XXXXXXXXXXXX,PTdd4lmb6art535085XXXXXXXXXXXXXXXXXXXXX

What variables change?

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 left-hand side.

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

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

proj_auth_df - This is the data frame that is formed from the csv of authorization credentials.

The Code

import base64
import requests
from signalwire.rest import Client as signalwire_client
import pandas as pd


#IMPORT A CSV WITH COLUMNS TITLED 'API_Token' and 'Project_ID'
proj_auth_df= pd.read_csv("/Path/To/Authorization/file/ALL_Projects_AuthCreds.csv")

# Then we can use any given ProjectID and API Token to make API calls that do not need to be project specific
space = 'SPACE NAME.signalwire.com'
auth = proj_auth_df['API_Token'][0]
proj = proj_auth_df['Project_ID'][0]


# For our Relay-Rest APIs we need a base64 encoded token of our projectID and API Token
base_64_token = proj + ':' + auth
message_bytes = base_64_token.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base_64_token = base64_bytes.decode('ascii')

# We declare our client so we can use functions from the python SDK
client = signalwire_client( proj , auth , signalwire_space_url = space)

# The Campaign Registry APIs are Relay-Rest so we must make an http request to the end points
# and declare what content to accept. We must also declare the content type and our Authorization Token which is base64 encoded

headers = {
    "Accept": "application/json",
    "Content-Type": "application/x-www-form-urlencoded",
    "Authorization": "Basic "+ base_64_token}


# Declare the url for our listing Brands API this will allow us to create an array of each brand SID for further API requests
list_brands_url= "https://"+ space + '/api/relay/rest/registry/beta/brands?page_size=50'

# Make the complete API request for our List Brands API
list_brands_API_Request = requests.request("GET", list_brands_url, headers=headers)

# Read the response from the API by accessing the json that was returned
list_brands_json = list_brands_API_Request.json()

# Find out how many brands are included in this project and create an array of that length
len_list_brands_json= len(list_brands_json['data'])
len_list_brands_json= range(0, len_list_brands_json)

# Create an array to list all Brands from our jsonString.  brand_sid refers to the 32 character id that SW gives your Brand
# brand_ID refers to the 7 character id given from the campaign registry
brand_sid_list=[]
brand_ID_list=[]

# Find what each of the numbers in this campaign are are by pulling the proper index, use our len_json to search through each part of our JSON
for i in len_list_brands_json:
    brand_sid = list_brands_json['data'][i]['id']
    brand_sid_list.append(brand_sid)

# Make a list of all BrandIDs by appending a list each time we find a new index in the JSON returned from List Brands API
    Brand_ID = list_brands_json['data'][i]['csp_brand_reference']
    brand_ID_list.append(Brand_ID)


# Now that we have an array of our Brand IDs and Brand SIDs, we need to create an array of all of our Campaign SIDs
# so that we can ake other API requests that ask for campaign_sid. Once we have our campaign_sid we can use
# the List All Number Assignments API

# Create an array for listing Campaign IDs and Sids
campaign_SID_list=[]

# We list the campaigns for every brand by listing each campaign of a given brand, and then repeating this process for every brand
for x in brand_sid_list:
    list_campaigns_url = "https://" + space + '/api/relay/rest/registry/beta/brands/' + x + '/campaigns'

    campaign_response = requests.request("GET", list_campaigns_url, headers=headers)

    # Read our response and use response.json() to print the entire object
    jsonString = campaign_response.json()

    # Find Number of campains in each brand so that we can iterate through each campaign
    num_of_camp = len(jsonString['data'])
    if  num_of_camp== 1:
        campaign_sid = jsonString['data'][0]['id']
        campaign_SID_list.append(campaign_sid)
    else:
        num_of_campaigns=list(range(0,num_of_camp -1))
        for i in num_of_campaigns:
            campaign_sid = jsonString['data'][i]['id']
            campaign_SID_list.append(campaign_sid)


# Lets now begin building our dataframe. We will start by declaring an array for each column that will be used
proj_name=[]
DID_list=[]
DID_status_list=[]
#Campaign_SID_DID=[]
campaign_ID_list=[]

# The list number assignment API will only return JSON data
# for the DID if it is in the project that we declare in our base64 encoded authorization header

# This means that we will loop through each 10dlc project through their ProjectID and API token. We will change
# the declaration of the 'client' for the SDK, and change the authorization header for any http request made.

# We have already made a csv of project_IDs and API_Tokens so that we can upload this and translate into a dataframe.

number_of_10DLC_projects= len(proj_auth_df)
number_of_10DLC_projects= range(0, int(number_of_10DLC_projects))

for p in number_of_10DLC_projects:

    auth = proj_auth_df['API_Token'][p]
    proj = proj_auth_df['Project_ID'][p]

    base_64_token = proj + ':' + auth
    message_bytes = base_64_token.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    base_64_token = base64_bytes.decode('ascii')

# This code is going to take a while to run, lets give ourselves some reminders of where we are at in the process
# Give a little heads up in the console of what projects are running for our code
    project_name = client.api.accounts(proj).fetch()
    friendly_name = (project_name.friendly_name)
    print('We are now digging through the data for project: ' + friendly_name )


    # We declare our client so we can use functions from the python SDK
    client = signalwire_client(proj, auth, signalwire_space_url=space)

    # The Campaign Registry APIs are Relay-Rest so we must make an http request to the end points
    # and declare what content to accept. We must also declare the content type and our Authorization Token which is base64 encoded

    headers = {
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": "Basic " + base_64_token}

    # List Dids Specific to this project
    Project_DID_list = []

    for i in campaign_SID_list:
        list_numbers_url = "https://"+ space + '/api/relay/rest/registry/beta/campaigns/'+ i + '/numbers'

        DID_response = requests.request("GET", list_numbers_url, headers=headers)

        # Read our response and use response.json() to print the entire object
        DID_response_jsonString = DID_response.json()
        # print("Json String that is pulled from our Campaign DID API looks like: ")
        #print(jsonString)
        num_of_DIDs = len(DID_response_jsonString['data'])

        # To easily keep track of when we need to iterate through multiple numbers in a campaign, or when we only have one number
        # we have created two loops below to address each scenario
        if num_of_DIDs == 1:
            DID = DID_response_jsonString['data'][0]['phone_number']['number']
            DID_list.append(DID)
            Project_DID_list.append(DID)

            DID_status= DID_response_jsonString['data'][0]['state']
            DID_status_list.append(DID_status)

            DID_Campaign=DID_response_jsonString['data'][0]['campaign_id']
            #Campaign_SID_DID.append(DID_Campaign)

            # Get the Campaign ID of the Number using our Campaign SID
            # We use the variable i to indicate the campaign_SID
            Retreive_Campaign_URL= 'https://'+ space +'/api/relay/rest/registry/beta/campaigns/' + i
            Retreive_Camapign_Response = requests.request("GET", Retreive_Campaign_URL, headers=headers)
            Retreive_Campaign_jsonString = Retreive_Camapign_Response.json()
            campaign_id = Retreive_Campaign_jsonString['csp_campaign_reference']
            campaign_ID_list.append(campaign_id)
            #print(Retreive_Campaign_jsonString)

            # Find Project Name
            account = client.api.accounts(proj).fetch()
            proj_name.append((account.friendly_name))
            #print(proj_name)
            print('New row added for number  ' + DID)


        if num_of_DIDs >> 1:
            num_of_DIDs = list(range(0, num_of_DIDs)) # Bug Fix- took away -1 from length
            for x in num_of_DIDs:
                DID = DID_response_jsonString['data'][x]['phone_number']['number']
                DID_list.append(DID)
                Project_DID_list.append(DID)

                DID_status = DID_response_jsonString['data'][x]['state']
                DID_status_list.append(DID_status)

                DID_Campaign = DID_response_jsonString['data'][x]['campaign_id']
                #Campaign_SID_DID.append(DID_Campaign)

                # Get the Campaign ID of the Number using our Campaign SID
                # We use the variable i to indicate the campaign_SID
                Retreive_Campaign_URL = 'https://' + space + '/api/relay/rest/registry/beta/campaigns/' + i
                Retreive_Camapign_Response = requests.request("GET", Retreive_Campaign_URL, headers=headers)
                Retreive_Campaign_jsonString = Retreive_Camapign_Response.json()
                campaign_id = Retreive_Campaign_jsonString['csp_campaign_reference']
                campaign_ID_list.append(campaign_id)
                #print(Retreive_Campaign_jsonString)

                # Find Project Name
                account = client.api.accounts(proj).fetch()
                proj_name.append((account.friendly_name))
                #print(proj_name)

                print('New row added for number  ' + DID)
# ADD ADDITIONAL FEATURES BELOW ME!!!!!

# We are so close to being done! All that is left is to turn all of these arrays into one large DataFrame named final_dataframe
final_dataframe= pd.DataFrame(({'Project_Name':proj_name, 'DID': DID_list, 'DID_Status': DID_status_list,
                                'Campaign_ID': campaign_ID_list }))

# Display all rows and columns of the final_dataframe
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)

# Lets print out our dataframe and see what this all looks like
print(final_dataframe)
final_dataframe.to_csv('Campaign_Reg_SampleOUTPUT.csv', index=False, encoding='utf-8')

Output

📘

Now that you know the basics, let's dig deeper...

They are called our Compatibility APIs for a reason, they are very compatible with your application!

You can take this code and run with it if this is enough for you. Nothing else is needed. But I'd recommend continuing reading so you can see how easy it is to integrate SignalWire APIs and gather even more data about the activity of your space.

Add all Unregistered Numbers in our space to the data table

Want to find out which of your numbers have not yet been associated to a campaign? No problem.

Alter the code above by adding the snippet that is referenced below at line 207. This snippet will list out all numbers that are present in your project via API and compare them to the numbers that are already present in your data table as having a campaign assignment.

this_proj_nums=[]

for p in number_of_10DLC_projects:
    space = space
    API_Token = proj_auth_df['API_Token'][p]
    Project_ID = proj_auth_df['Project_ID'][p]

    # We declare our client so we can use functions from the python SDK
    client = signalwire_client(Project_ID, API_Token, signalwire_space_url=space)

    # Find Name of the given project
    Project_ID_API = client.api.accounts(Project_ID).fetch()


    # List all Numbers in accounts that have a campaign associated
    incoming_phone_numbers = client.incoming_phone_numbers.list()

    for record in incoming_phone_numbers:
        this_proj_nums.append(record.phone_number)

# Determine if number is already listed in our dataframe, and if not, append our unregistered_numbers array

# Find length of unregistered_numbers and append the remainder of columns in our dataframe

    number_nums_in_proj= len(this_proj_nums)

    if number_nums_in_proj > 0:

        for x in this_proj_nums:
                exist_count = DID_list.count(x)
                if exist_count > 0:
                    print(x + 'is already associated with a campaign')
                else:
                    print(x + 'is not associated with a campaign')

                    DID_list.append(x)
                    proj_name.append((Project_ID_API.friendly_name))
                    DID_status_list.append('NOT ASSOCIATED')
                    campaign_ID_list.append('NA')

    this_proj_nums = []

Add Messaging Activity to our Data Table

This last feature to our snippet will use the List All Messages API to search through each number and find when it was last used and also how many messages were sent from it.

This API requires the proper project ID and API token to be included for a given number, so we will be embedding this code into our loop of all projects. This is represented as for p in number_of_10DLC_projects:

To run this snippet, copy the below snippet and paste it into the above code at line 205. Make sure that you delete all of the code below line 205 before pasting in the below code.

# This is the part of the code that you must enter if you would like to incorporate information on messaging activity.
# The below code will create columns for the last time the number was used, as well as the total number of messages sent

# Lets pull up some data on the messaging activity of these numbers
# We will use our DID_List to list the date of each message sent from a given number

# Total Number of Messages Sent
    message_date=[]
    for i in Project_DID_list:
        message=client.messages.list( from_=i)
        for record in message:
            message_date.append((record.date_sent))

        # Append the Num_Mess_Sent array with the number of messages sent by the number being analyzed
        Number_of_messages_this_number_sent = (len(message_date))
        Num_Mess_Sent.append(Number_of_messages_this_number_sent)

        # Append our dataframe with the time of the most recent message sent. If no messages have been sent then add a note saying 'not used yet'
        if Number_of_messages_this_number_sent == 0:
            DID_last_used.append('not used yet')
        else:
            DID_last_used.append((message_date[0]))


        print('New row added for number  ' + i)


# We are so close to being done! All that is left is to turn all of these arrays into one large DataFrame named final_dataframe
final_dataframe= pd.DataFrame(({'Project_Name':proj_name, 'DID': DID_list, 'DID_Status': DID_status_list,
                                'Campaign_ID': campaign_ID_list, 'Date_Last_Used': DID_last_used,
                                'Total_Number_Messages_Sent':Num_Mess_Sent }))

# Display all rows and columns of the final_dataframe
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)

# Lets print out our dataframe and see what this all looks like!
print(final_dataframe)
final_dataframe.to_csv('ALL_Number_Assignments_and_Messaging_Info.csv', index=False, encoding='utf-8')

Comments

This snippet introduced a few different techniques to incorporate data given by SignalWire's Compatibility APIs as well as the Campaign Registry APIs. We learned how to list brands, list campaigns, list number assignments, and even pull more data on each of these numbers. Lastly, through the usage of the pandas package, all of this data was formatted in a table and exported to csv.


Did this page help you?