It’s cool to be able to interact with publicly available API’s so you can grab weather reports, live travel updates or access your twitter feed. But even better, it’s actually pretty straightforward to create your own API using python and the Flask web framework and Flask-RESTful library.
What’s the point of an API rather than standard website? Mainly because APIs are a standard format that make it easy for computers to exchange information, no matter what programming language is used or what platform it is delivered on. For example twitter have a website, a mobile app for various different platforms, but they all need to access the same data over the web. Rather than having to design a way to access this for each app platform, they can all access the API, such that the back end (Server, main program functions and database) is made available through the API and is independent of the front end (app, website, graphical user interface or AndyPi LCD, etc). It’s not quite as simple as that, but that’s the basics.
Furthermore, if you need some code to respond to a webhook, you’ll need your own API to do that, which is what this example shows. See my article: ‘What is a webhook?’ if you don’t know what that is.
For this project, my client wanted to execute some code to send their users an (digital) product whenever they made a purchase through their online payment gateway, Chargify, which can send a webhook in response to various events. Prior to writing the Python code to deal with this we needed to look at the Chargify webhook documentation and set this up from the client’s Chargify account, following these steps:
- Enable webhooks in the Chargify dashboard
- Select which webhooks to send (payment_success in this case)
- Enter the API URL that accepts the webhook
For part three, this will obviously be the URL of our python-flask API which we haven’t written yet! I temporarily used Request Bin as a debugging tool instead. I entered my Request Bin URL endpoint in Chargify, and the dashboard allows you to manually send sample webhooks. Then, back in Request Bin, we can see exactly what has been sent – which data about the Chargify user and their new purchase (POSTed in JSON format to our endpoint).
The API example I’m going to walk through here has just one method – to receive this HTTP ‘POST’ request. ‘POST’ requests are like filling in a form on a website, hitting the ‘submit’ button and posting this data to the website for it do something with the data. In this example the API does not receive ‘POST’ data from a website form, but from the webhook.
Let’s go through this step by step – look at the github gist for the full code
Above the normal things needed for a flask app, we need very little in addition. We just need to import Api from the Flask-restful extension and create a new instance of this object, wrap our code to be executed when the API is called in a class, and finally link this ‘Resource’ to an endpoint URL:
from flask.ext.restful import Api, Resource api = Api(app) class Customer_Signup(Resource): def post(self): # code here api.add_resource(Customer_Signup, '/api/customer_signup/')All of the following code goes in the post() function in Customer_Signup class
1. Webhook Authentication
This section is an extremely important part of webhook and api handling. Since our api endpoint is live on the web, anyone could send something to it. It would not be difficult for someone to find the endpoint, copy the chargify webhook post, and get access to our signup process. All webhook / apis should have authentication to avoid this. Chargify sends a webhook signature with the webhook POST request which we can check is authentic. This signature is created by taking the entire webhook POST data, and doing a 256SHA hash using the chargify shared key (available from the chargify account). We can re-created this if we know the key, using the python hmac.new function, and check it is the same as the one sent to the api endpoint.2. Check the webhook id has not been processed already
Chargify will keep sending the webhook if it encounters any problems in delivery or not recieving a 202 response in time. So this section just make sure we only process each webhook once, just in case anything goes wrong and it gets sent again. This is pretty easy since each webhook has a unique id, so we just need somewhere to save this id, so future requests can check that it has not been processed already. For this I’m using redis, which is better than using a file system based database for temporary storage like this, plus I’m using it for celery too.3. Get the customer_id from the webhook payload
Since our webhook data has already been parsed into a nested set of python dictionaries, we can easily access the customer id using python dictionary notation.4. Call the main function to be executed (user celery for long running tasks)
This is where the real work is done – we call a function (although I haven’t shown what this is my my example) and simply pass the chargify customer id. In reality this task takes a little while to run, so it needs to be executed in parallel (using a seperate thread or celery – see here for a brief explanation) because….5. Tell chargify we have processed this webhook correctly (within 10 seconds)
…. we need tell chargify within ten seconds that the api endpoint has accepted the webhook – otherwise it will assume it has failed. All we need to do for this bit is return a HTTP 202 response, which means received ok.So that gives you the basic framework for handling any webhook, whether it is a notification of a new customer from a payment gateway or any other event.