Connecting Calls

This guide assumes that we have the the Sift library available and Flask installed (This is only necessary if you intend on actually running the provided code snippets). It also assumes we’ve already set up our account with the Sift API, which will supply us with our auth token that we’ll use to authenticate requests.

Setting up an Application

First off, we need to make an Application. An application is responsible for telling Sift what to do when new Connections are created. This happens when someone calls a phone number we have registered with Sift or when a user of our service creates an outgoing connection via the javascript Sift VOIP Library. To figure out what actions to take with the resulting Connection object, Sift makes an HTTP POST request to a callback URL we provide for an application, allowing us to respond with a list of commands (known as a routine) that tells Sift what to do with the new connection.

Ok, that’s a lot to take in. But we’ll address each step in turn. First let’s just make our application. We need only to make a POST to the Create an Application endpoint with the necessary information. We’ll be using the python requests library to handle our HTTP requests.

import requests

data = {
    'name': 'SuperCoolApplication',
    'on_incoming': 'https://ourserver.com/on_incoming'
}
requests.post('https://api.gridspace.com/v0/applications', data, auth=(ACCOUNT_ID, AUTH_TOKEN))

Note

HTTP basic access authentication is required for all calls to our REST API. Refer to API Authentication for more information.

The name is just a human readable name we choose, and the on_incoming field contains the callback URL mentioned above. We’ll get to using it a bit later. Now that we’ve done that, let’s start making calls.

Calling a phone

To start off, we’ll call a phone number of our choosing, play some text using the text-to-speech (TTS) feature once they’ve picked up, and then hang up. Simple enough.

We start by simply making a POST to the connections endpoint:

data = {
    'phone_number': '+15554443333',
    'status_url': 'https://oursite.com/say_hello'
}
requests.post('https://api.gridspace.com/v0/connections', data, auth=(ACCOUNT_ID, AUTH_TOKEN))

We have passed two parameters to our request: the phone number to call and a callback URL to use when the established connection changes. The phone number should be an E.164 formatted phone number with a ‘+’ and country code.

The status URL points to an endpoint we must set up to handle changes in the connection to our callee. It will be used by Sift to communicate with us when the connection is created or its status changes. Whenever this happens, Sift will make a POST request to the URL with a JSON structure containing the Connection object in the connection field.

The next step is implementing this URL endpoint that will accomplish what we want.

import json
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/say_hello', methods=['POST'])
def say_hello():
    """Say hello to the person we call"""
    connection_status = json.loads(request.data)['connection']['status']
    if connection_status == 'connected':
        response = {
            'routine': [
                {
                    'name': 'Say',
                    'text': "Hello there. I'm definitely not a robot. Goodbye."
                },
                {
                    'name': 'HangUp'
                }
            ]
        }
        return jsonify(response)
    return ''

All we’ve done here is check the status in the Connection object to see if it is connected (meaning the person has picked up their phone), and if so returned a routine for the API to execute. A routine is simply a list of commands that will be executed sequentially. For more information about the different types of commands we can send here, see the routines documentation.

Calling a WebRTC endpoint

We’ve learned how to connect two people on their phones, but phones are old and we all love our computers. So let’s now allow users to call their friend’s phone using their browser.

To do so we’ll need to download the javascript Sift VOIP library, and include it in the page we serve to our users. This will make a global Sift object available, which will allow us to do everything we need. The client library uses WebRTC, so this will only work in browsers that support WebRTC.

On our server, we need to use the Sift Helper Library to first generate a capability token that we pass to our client and use with the Sift VOIP library:

import sift

capability = sift.GridspaceCapability(account_id, account_token)
capability.allow_client_outgoing(application_id)
client_token = capability.generate()

Here we are using the account_id, account_token, and application_id that are available on our account management page. We call allow_client_outgoing to authorize the client to make outgoing calls. Once we pass this token to our client, we can use it to initialize the Sift VOIP library:

// Call somewhere in our frontend javascript code
Sift.init(client_token);

After the init() function has been invoked, we can call out to our friend as follows:

function callFriendsPhone(friendsPhoneNumber) {
    var clientData = {phone_number: friendsPhoneNumber};
    Sift.connect(clientData);
}

This will prompt the user for microphone access and initiate the connection request.

So now what happens? Once Sift sees the outgoing connection request from the application, it will make a POST to the on_incoming callback url associated with the application (the URL we provided when we set up our application). This POST will contain a JSON object with a Connection object in the connection field. In addition to the standard fields, the Connection object will also contain a client_data field that includes any data we passed to the Sift.connect() call in our client.

In the response to this POST, we simply have to tell Sift what to do – namely, to call the given phone number. To do this, we use routines, just as we did in the previous guide:

import json
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/on_incoming', methods=['POST'])
def voice_url():
    client_data = json.loads(request.data)['connection']['client_data']
    response = {
        'routine': [
            {
                'name': 'CallPhone',
                'phone_number': client_data['phone_number'],
            }
        ]
    }
    return jsonify(response)

This will now allow our users to call their friends right from within their browser. But what if their friends don’t like phones either? We can also allow our users to recieve calls from within their browsers. We’ll just need to say so when we create our capability token:

# Same as before
capability = sift.GridspaceCapability(account_id, account_token)
capability.allow_client_outgoing(application_id)

# Now add support for incoming calls
friends_client_name = ...  # something to uniquely identify the client
                           # among all clients that use capability tokens
                           # generated from our account
capability.allow_client_incoming(friends_client_name)

client_token = capability.generate()

Then in our client code we can add support for calling to a friend’s browser:

function callFriendsBrowser(friendsClientName) {
    var clientData = {client_name: friendsClientName};
    Sift.connect(clientData);
}

and in our handler we can check to see whether we passed a phone_number or client_name and then branch accordingly:

@app.route('/on_incoming', methods=['POST'])
def voice_url():
    client_data = json.loads(request.data)['connection']['client_data']
    if 'phone_number' in client_data:
        response = {
            'routine': [
                {
                    'name': 'CallPhone',
                    'phone_number': client_data['phone_number'],
                }
            ]
        }
    else:
        response = {
            'routine': [
                {
                    'name': 'CallClient',
                    'client_name': client_data['client_name'],
                }
            ]
        }
    return jsonify(response)

See CallPhone and CallClient for more details on the options they accept.

Receiving an incoming call

To receive incoming phone calls we will first have to register an available phone number to our application. To find the available phone numbers, we make an HTTP GET request to the available phone numbers endpoint.

country_code = 'US'  # The ISO 3166-1 alpha-2 format country code of our country
response = requests.get(
    'https://api.gridspace.com/v0/availablenumbers/' + country_code,
    auth=(ACCOUNT_ID, AUTH_TOKEN))
available_numbers = response.json()

Once we pick a number from this list, we can make a POST to the phone numbers endpoint to register it:

our_favorite_number = available_numbers[0]  # We're not picky. We'll just take the first one
data = {
    'phone_number': our_favorite_number,
    'application_id': application_id
}
requests.post('https://api.gridspace.com/v0/phonenumbers', data, auth=(ACCOUNT_ID, AUTH_TOKEN))

Note that we’ve needed to include the ID of our application object so that the Incoming Connection Callback will be tied to the phone number.

Once we’ve registered a phone number for our application, support for incoming calls follows the same flow as given above. That is, when someone calls the phone number, Sift will make an HTTP POST request to the on_incoming URL associated with the application, at which point we can decide what to do with the connection.

As an example, the following on_incoming handler will ensure that all calls to the registered number will be rerouted to the number “+15554443333”:

@app.route('/on_incoming', methods=['POST'])
def voice_url():
    response = {
        'routine': [
            {
                'name': 'CallPhone',
                'phone_number': "+15554443333",
            }
        ]
    }
    return jsonify(response)

Now whenever someone calls the purchased phone number, they will hear the standard ringback tone but they will be calling “+15554443333”.