How to Build a Serverless Slack API with Django and Zappa

If you or your company uses Slack (you probably do), then you already know how much potential Slack’s API has to offer. Custom Slack bots, event subscriptions, slash commands, and a multitude of other functionality are transforming how teams communicate and organise information.

With all of the advances in serverless and event-driven technology, it is becoming even easier to build useful automations and internal tools.

There are many different ways to use Slack with serverless, but one particularly powerful combination (and my favorite) involves the Python framework Django. In this guide I will walk you through the process of building on the rock-solid foundation of Django with the super easy to use serverless Python library Zappa.

First things

This guide assume that you possess the following:

  • AWS account with credentials available on your local machine so that Zappa can talk to AWS.
  • Postgres AWS RDS with a VPC security group, this will be necessary for storing the Slack data.
  • A Slack workspace with permission to install applications.

The AWS database requirements may seem a bit daunting at first, but once you have it configured the rest of this process will be easy — promise!

Step 1: Create your Slack app

We are first going to create our Slack app. This step is just to get the credentials gathering out of the way, and then we will come back later to actually configure the app.

  • Log into your Slack workspace and visit to create a new app.
  • Under the Add features and functionality section, click Bots to create your Bot User.
  • After adding the Bot, you should next click Install App to Workspace button under Install your app to your workspace. This will allow you to authorize the app and Bot User to be used in your workspace.
  • Now we’ve done enough to have all of the Slack credentials that we will need to interact with the API.
  • Click on OAuth & Permissions, you will see two token fields, we just need to copy Bot User OAuth Access Token, this will be used as our SLACK_BOT_USER_TOKEN environment variable.
  • Next click on Basic Information and scroll down to App Credentials. We will copy the Client ID for the SLACK_CLIENT_ID and the Client Secret as SLACK_CLIENT_SECRET. An finally, copy the Verification Token to be used as SLACK_VERIFICATION_TOKEN.
  • Now that we have our credentials, add them to your shell as environment variables. Later on in the guide we will also have to use these values in the Zappa configuration, but right now you can include them in your local environment:
export SLACK_CLIENT_ID='your-credential'
export SLACK_CLIENT_SECRET=’your-credential'
export SLACK_VERIFICATION_TOKEN='your-credential'
export SLACK_BOT_USER_TOKEN='your-credential'

That’s it for Slack at the moment, we will finish configuring the app during the deployment stage. Next we will get the Django project and example app running locally.

Step 2: Start your Django project

You will want to create a Python virtualenv for use with a Django 2.0 project and Python version 3.6. More advanced setups may use Docker, but we won’t delve into that for the purpose of getting this running quickly. There are several options for creating a virtualenv, this guide will use pyenv.

Important: the name of your virtualenv must NOT match the name of your Django apps or you will run into issues during deployment.

Assuming you have pyenv and a version of Python 3.6, you can follow these steps at the command-line to get the project requirements prepared:

# Create the virtualenv
pyenv virtualenv 3.6.4 slackproj
# Activate it
pyenv activate slackproj
# Install the requirements from pypi
pip install django django-rest-framework django-rest-slack psycopg2-binary requests
# Create the Django project
django-admin startproject example
# Enter the project directory and create our example app
cd example/
./ startapp slackapp

This will install all of the requirements necessary to run our application and prepare the Django app. This uses django-rest-slack — a reusable Django app that I created to provide a simple means of handling and storing Slack request data via an API using django-rest-framework components.

Step 3: Configure the Django project

Now that we have the requirements installed and the project started, we can begin configuring the settings.

First let’s modify our project settings file examples/ by including our test app and its dependencies in the INSTALLED_APPS list:


Next we will edit the url settings in examples/ to make the event and command API endpoints available:

from django.conf.urls import include
from rest_slack.views import DRSEventView, DRSCommandView
api_patterns = ([
path('events/', DRSEventView.as_view()),
path('commands/', DRSCommandView.as_view()),
], 'api')

urlpatterns += [
path('api/v1/', include(api_patterns))

The base Slack model uses the Postgres JSONField type, so you will want to create a Postgres database for local development. This configuration is only for local testing, the Zappa deployment will use the Amazon RDS.

Note: You do not need to use Postgres or the base Slack models to use the rest of the functionality django-rest-slack provides, but it is recommended for the example presented in this guide.

Create a database called slackexample using the command createdb slackexample then edit the example/ file again with the following:

'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'slackexample'

We will only be using this database configuration for local development, the Zappa deployment will use the Amazon RDS.

Let’s create our models for storing the data. They will inherit from the abstract base model in the django-rest-slack app, add the following to your slackapp/ file:

from rest_slack.models import SlackModel

class SlackAppSlackModel(SlackModel):
"""Model for storing slack data"""

This model possesses two fields, type and data, and you can extend it. Go ahead and inspect the model source here.

Now run the: ./ makemigrations && ./manage.migrate

Step 4: Define functions to handle the API requests

At this point we have the API endpoints setup and the database model to store the Slack data — now we need to define our handler functions. The django-rest-slack app uses a registry that is based loosely on Django’s builtin templatetag library.

You will create a file called within your app directory, define the methods to be used with slash commands and events, then register them to be included in lookups during API requests.

Create the functions file in slackapp/ with the following content:

from rest_slack.registry import Registry
from rest_slack.utils import save_slack_data
from slackapp.models import SlackAppSlackModel
register = Registry()
def reaction_added(data):
Register the reaction_added event and save the data.
save_slack_data(data, SlackAppSlackModel)
def slashtest(data):
Register the /slashtest command, save the data, return response.
save_slack_data(data, SlackAppSlackModel)
return {
'text': 'Testing the api',
'response_url': data['response_url']

We map our functions to slash commands and events using the@register.function decorator. The functions must either be the name of a specific Slack event type or a defined slash command.

Note: Event functions do not return anything, if you would like to respond to events sent by the Slack Event API, then you will need to manually send a request from your event function — or wait for me to add the functionality to django-rest-slack. :)

Step 5: Test it locally first

Now that we have some functions registered, let’s test things with some fake data to make sure everything is setup correctly. We are going to create a file to mock the behaviour of the Slack event and command requests. Create a file example/ with the following:

import os
import requests
"token": os.environ.get('SLACK_VERIFICATION_TOKEN'),
"team_id": "T0001",
"team_domain": "example",
"enterprise_id": "E0001",
"enterprise_name": "Globular%20Construct%20Inc",
"channel_id": "C2147483705",
"channel_name": "test",
"user_id": "U2147483697",
"user_name": "Steve",
"command": "/slashtest",
"text": "94070",
"response_url": "",
"trigger_id": "13345224609.738474920.8088930838d88f008e0"
"token": os.environ.get('SLACK_VERIFICATION_TOKEN'),
"team_id": "T061EG9RZ",
"api_app_id": "A0FFV41KK",
"event": {
"type": "reaction_added",
"user": "U061F1EUR",
"item": {
"type": "message",
"channel": "C061EG9SL",
"ts": "1464196127.000002"
"reaction": "slightly_smiling_face"
"event_ts": "1465244570.336841",
"type": "event_callback",
"authed_users": [

slash_test =, 'http://localhost:8000/api/v1/commands/')
event_test =, 'http://localhost:8000/api/v1/events/')

Now to run the test, we will do the following:

  • Run the local server with ./ runserver
  • Run the test file with python

If everything is working, then we should see a HTTP 200 responses. Next we will create a way of looking at our raw data:

  • Create a superuser with ./ createsuperuser
  • Create a file slackapp/ with the following:
from django.contrib import admin
from slackapp.models import SlackAppSlackModel
class SlackAppAdmin(admin.ModelAdmin):
"""Simple admin view for looking over data""", SlackAppAdmin)

Log-in to the admin at http://localhost:8000/admin using your superuser details and inspect the data that was created. In the slackapp modeladmin you should see two records created for each of our registered functions:

We did it! Well, almost…

Step 6: Deploy the Django application to AWS Lambda using Zappa

There are many ways to deploy a Django application and they should all work with this example, but in this guide I will be giving a simple rundown of how to complete our serverless AWS Lambda deployment with Zappa in three easy steps:

  • To begin, you need to pip install zappa into your virtualenv.
  • Run zappa init from your project directory and follow the prompts to generate your initial zappa_settings.json file. The defaults will be fine for now.
  • Finally deploy your app: zappa deploy dev

If everything was successful Zappa will have handled all the details of configuring AWS to deploy your application.

Super easy, right?

Step 7: Additional configuration for RDS and Slack

Now before we can actually use the deployment, we need to make a few configuration changes. Since we are storing data, we need to include a Postgres Amazon RDS in both our Django project and Zappa configurations.

We also need to include our Slack app credentials as environment variables in our Zappa settings and add our deployment’s hostname to our Django ALLOWED_HOSTS list.

  • Include the VPC subnets and security group associated with your Amazon RDS and Slack environment variables in zappa_settings.json:
"vpc_config" : {
"SubnetIds": [ "subnet-<id>", "subnet-<id>", "subnet-<id>" ],
"SecurityGroupIds": [ "sg-<id>" ]
"environment_variables": {
"SLACK_CLIENT_ID": "your-credential",
"SLACK_CLIENT_SECRET": "your-credential",
"SLACK_VERIFICATION_TOKEN": "your-credential",
"SLACK_BOT_USER_TOKEN": "your-credential"
  • Now add the AWS RDS and hostname details to example/
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': '<dbname>',
'USER': '<dbuser>',
'PASSWORD': '<dbpassword>',
'HOST': '<dbhost>',
'PORT': '5432',
  • Re-deploy the app using zappa update dev and and navigate to your deployment in the browser.

Now the deployment is up and running and should be ready to handle requests. Time to return to where we started and configure the Slack app.

Step 8: Create a Slack slash command and event subscription

Head to the settings area for the Slack app that you installed in your workspace previously. The first thing we will be doing is creating the slash command that will correspond to the function we registered in the slackapp/ file.

  • Create a new slash command, call it /slashtest to match the name of our function handler.
  • Set your deployment’s API endpoint as the command’s request URL: <https://<yourhost>/dev/api/v1/commands/

Then save and re-install your app when prompted.

Next create a new event subscription, set the request URL to the event handler endpoint: <https://<yourhost>/dev/api/v1/events/

Slack will immediately test this endpoint for the correct verification token. After it is verified, subscribe to the reaction_added event.

Step 9: Test the commands in Slack and inspect the data

The Slack app should be communicating with our API whenever our event occurs or the slash command is run. Let’s go ahead and test the events from slack:


The bot is running and the API is handling the slash command, but to be certain it is being stored properly, we will want to confirm through the Django admin. To do this, it is necessary to create a superuser.

How do you create a superuser using Zappa? The easiest way to do this is to use zappa invoke:

zappa invoke --raw dev "from django.contrib.auth.models import User; User.objects.create_superuser('admin', '', 'passwordhere')"

Now point your browser to the deployment at https://<yourhost>/dev/admin and log-in using the superuser you’ve just created. Since some additional configuration is required for static files to be served the interface will be un-styled, but you will still be able to access the data:

You can now make additions and changes to your deployment and usezappa update dev to update it without the hassle of using a traditional server.

That’s it! You are live!

This example is pretty simple and represents the bare-minimum involved to achieve this particular functionality. I would recommend following this guide to learn more about what is possible using Zappa and to configure more advanced deployments.

Contributions and bugfixes to django-rest-slack are welcomed— it was created to make building Slack API handlers easier.

Also, if you’re ever looking for a company to design or develop your vision into a reality, then drop us a line at our website and feel free to follow us on Twitter @airteamaus. We love building things. :)