We’ve just released receiving SMS’es as a beta and what better way to celebrate the launch of this often requested feature than by doing a small tech demo?

For this demo I will present a small API project that allow us to receive a question via SMS, query wolfram alpha for a reply and then respond via SMS.

What follows is a quick tutorial on how to do this yourself, explaining the overall steps along the way for a better understanding of the tech involved. If you just want to try it out, and you got a danish mobile subscription, text wolfram followed by your question to 1204. Ie. send “wolfram temperature copenhagen” to 1204.

We can’t make any guarantees about the availability of this wolfram tech demo, there are limits to ie. the number of API requests etc. However you can easily make your own with the instructions below.

Also please note that Wolfram Alpha needs to think about what you are asking, so it might take a while to fetch your answer. :)

Prerequisites

For this demo you’ll need a Wolfram Alpha APP ID. You get this free, by signing up with Wolfram Alpha.

You’ll also need a GatewayAPI account, which you can get on this site for free. However in order to receive a SMS, you’ll need a short code and/or keyword to which the user sends the SMS. This short code and keyword is leased to you, so when we receive a SMS on the specific short code, with the specific keyword, we know where to deliver the SMS.

You can either lease a keyword on a shared short code, such as 1204, or you can lease an entire short code, such as +4560575797. Your account should already be set up with a keyword that starts with ‘test-‘ for testing purposes. Contact us via the live chat if you need a new short code and/or keyword.

Hello Ngrok

In order to deliver SMS’es to your service, your service/webhook needs to be made available on the internet so we can contact it when a new SMS arrives.

Ordinarily this means that you have to deploy your code to a webserver somewhere and testing suddenly takes ages. However a free service makes this really easy and quick: ngrok. Ngrok gives you a HTTP(S) endpoint on the internet where all requests are forwarded to your local server for easy webhook development.

We are also going to use Flask, a python based micro framework which is very suitable for this task. I hope that the code samples below are easy to follow even for non-python devs. As always if you have any questions, contact us via live chat or support@gatewayapi.com.

Download and unzip ngrok. Install deps with: pip install flask wolframalpha requests_oauthlib unidecode

Open wolfram.py in your favorite editor and paste the following.

from flask import Flask, request  # Framework
import wolframalpha               # For WolframAlpha Queries
from unidecode import unidecode   # For special replies
from requests_oauthlib import OAuth1Session  # To send SMSes
app = Flask(__name__)


@app.route('/')
def default():
    return 'Send me a SMS'

On the command line where you unzipped ngrok. Run ./ngrok http 5000. You will get a ngrok.io https url.

Run env FLASK_APP=wolfram.py flask run this will start a flask server on localhost port 5000. Ngrok will forward requests to flask, confirm this by visiting the ngrok.io URL in your webbrowser. You should get a page that reads “Send me a SMS”.

Receiving SMS’es

The ngrok url you got earlier must be configured as a web hook, and a keyword must be assigned to the web hook, so we will know to contact it when receiving a SMS.

Open the GatewayAPI Dashboard, go to Settings -> Web Hooks, add a new web hook and enter the ngrok URL in “Web hook URL” and click save. Then open the Keywords tab pane and assign a keyword to the web hook. GatewayAPI will now call your web hook whenever a SMS arrives for your keyword on your shortcode.

At the time of writing this post only REST web hooks support receiving SMS’es. Kannel etc will follow later.

Now we need to extend the flask API with a route that receives the SMS’es.

@app.route('/', methods=['POST'])
def wolfram():
    """
    An endpoint to receive a wolfram alpha query via SMS and send the
    results back via SMS to the user.
    """
    # Get the query from the MO SMS
    mosms = request.get_json()
    words = mosms['message'].strip().split()

    # Our query is everything that follows the first word
    query = ' '.join(words[1:])

Now we get a variable named query which contains everything the user wrote after the keyword itself. This will be our input to wolfram alpha.

Query wolfram alpha

Now we look up the query with wolfram alpha and format the reply. Replace “APP-ID-GOES-HERE” with your APP ID from wolfram alpha.

# ... continued from above
    # Look it up with wolframalpha
    try:
        client = wolframalpha.Client('APP-ID-GOES-HERE')
        res = client.query(query)
        reply = '\n'.join(a.text for a in res.results)
        if not reply and res.pods:
            reply = '\n'.join(a.text for a in res.pods if a.text)
        if not reply:
            reply = "Sorry, I don't know the answer to that one"
    except:
        reply = "Sorry, an error occured"

    # Convert special unicode characters from Wolfram Alpha
    reply = unidecode(reply)

Send the reply

All that is left now is to send the reply from wolfram alpha back to the user via SMS. Sending a SMS is easy with GatewayAPI. On our dashboard you can find pre-configured code samples for most languages. Select the python example and copy paste your API key and secret.

# ... continued from above
    # Send the reply back to the user (copy from GatewayAPI Dashboard)
    key = 'OC-YOUR-API-KEY-GOES-HERE'
    secret = 'Your.API.Secret.Goes.Here'
    gwapi = OAuth1Session(key, client_secret=secret)
    req = {
        'recipients': [{'msisdn': mosms['msisdn']}],
        'message': reply,
    }

    res = gwapi.post('https://gatewayapi.com/rest/mtsms', json=req)
    res.raise_for_status()

    # Reply back with a HTTP/204 (No Content) on success
    return ('', 204)

GatewayAPI.com keeps calling your web hook until you send a 2xx reply to let us know the SMS was received, so remember to return a reply at the end.

Final thoughts

Wolfram Alpha contains many good examples on what to ask it, including topics as Web and Computers, Video Games and Culture and Media.

Our two-way messaging feature is at the time of writing in the beta stage, and there are a number of improvements we will implement in the months that follow. Expect latency to improve and more shortcodes to be made available etc.

Complete code sample

Same as above, but included here in full.

from flask import Flask, request  # Framework
import wolframalpha               # For WolframAlpha Queries
from unidecode import unidecode   # For special replies
from requests_oauthlib import OAuth1Session  # To send SMSes
app = Flask(__name__)


@app.route('/')
def default():
    return 'Send me a SMS'


@app.route('/', methods=['POST'])
def wolfram():
    """
    An endpoint to receive a wolfram alpha query via SMS and send the
    results back via SMS to the user.
    """
    # Get the query from the MO SMS
    mosms = request.get_json()
    words = mosms['message'].strip().split()

    # Our query is everything that follows the first word
    query = ' '.join(words[1:])

    # Look it up with wolframalpha
    try:
        client = wolframalpha.Client('APP-ID-GOES-HERE')
        res = client.query(query)
        reply = '\n'.join(a.text for a in res.results)
        if not reply and res.pods:
            reply = '\n'.join(a.text for a in res.pods if a.text)
        if not reply:
            reply = "Sorry, I don't know the answer to that one"
    except:
        reply = "Sorry, an error occured"

    # Convert special unicode characters from Wolfram Alpha
    reply = unidecode(reply)

    # Send the reply back to the user (copy from GatewayAPI Dashboard)
    key = 'OC-YOUR-API-KEY-GOES-HERE'
    secret = 'Your.API.Secret.Goes.Here'
    gwapi = OAuth1Session(key, client_secret=secret)
    req = {
        'recipients': [{'msisdn': mosms['msisdn']}],
        'message': reply,
    }

    res = gwapi.post('https://gatewayapi.com/rest/mtsms', json=req)
    res.raise_for_status()

    # Reply back with a HTTP/204 (No Content) on success
    return ('', 204)