Slack Events API
Trigger Kestra flows based on Slack events.
The Slack Events API allows you to build apps that respond to events from Slack. For example, you can trigger a custom action anytime a user joins a channel or when someone reacts to a message with a specific emoji.
Create a Slack App
To use the Slack Events API, you’ll need to create a Slack app. You can do this from the Slack API website.
First, click on the “Create New App” button:
Choose the option “From scratch”:
Then, give your app a name and select the workspace where you want to install it:
Now, you need to enable the “Event Subscriptions” feature:
In the “Subscribe to bot events” section, you can add events you want to listen to.
For example, you can listen to the app_mentions
and reaction_added
events:
Create a flow with a Webhook trigger
You can now create a Kestra flow that will listen to the events you’ve subscribed to:
id: slack_eventsnamespace: prod
tasks: - id: process_slack_event type: io.kestra.plugin.core.log.Log message: "{{ trigger.body }}"
triggers: - id: slack_event type: io.kestra.plugin.core.trigger.Webhook key: superStrongSecretKey42
Note that the webhook key cannot contain any special characters — only letters and digits. Also, consider it as a secret that you should keep safe. You can use Kestra’s Secrets to store it securely.
Now, the only part left is to create a simple app that will listen to Slack events and will forward them to your Kestra flow via the Webhook trigger.
We’ll look at how to do this using Python and FastAPI. For deployments, we’ll show two options:
- Using Modal for easy deployment
- Using ngrok to expose our local FastAPI server to the internet. You can replace ngrok for any other deployment method you prefer.
Deploy a Slack app with Modal
First, sign up for a free account on Modal. Then, go to your Settings:
And create a new API token:
You will see a similar command:
modal token set --token-id ak-zzzzzzzzz --token-secret as-zzzzzzzzz
Now, create the following flow in Kestra and replace the token ID and token secret with the ones you got from Modal. You can use Kestra’s Secrets to store those securely. Also, make sure to replace your_kestra_host
with your Kestra host URL in the slack.py
file.
id: slack_appnamespace: prod
tasks: - id: modal_slack_app type: io.kestra.plugin.modal.cli.ModalCLI commands: - modal deploy slack.py env: MODAL_TOKEN_ID: "{{ secret('MODAL_TOKEN_ID') }}" MODAL_TOKEN_SECRET: "{{ secret('MODAL_TOKEN_SECRET') }}" inputFiles: slack.py: | import logging from fastapi import FastAPI, Request, BackgroundTasks from fastapi.responses import JSONResponse from modal import Image, Stub, asgi_app import requests
web_app = FastAPI() stub = Stub("slack_app")
image = Image.debian_slim().pip_install("requests")
logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__)
def process_event(event): # TODO adjust the URL below to your Kestra Webhook URL url = "http://your_kestra_host:8080/api/v1/main/executions/webhook/prod/slack_events/superStrongSecretKey42" headers = {"Content-Type": "application/json"} response = requests.post(url, headers=headers, json=event) logger.info(f"Forwarding event response: {response.status_code} - {response.text}")
@web_app.post("/slack/events") async def slack_events(request: Request, background_tasks: BackgroundTasks): json_data = await request.json()
if "challenge" in json_data: logger.info("Received Slack challenge event") return JSONResponse(content={"challenge": json_data["challenge"]})
logger.info(f"Received event: {json_data}")
# Process the event asynchronously background_tasks.add_task(process_event, json_data)
# Respond immediately to Slack logger.info("Responding immediately to Slack") return JSONResponse(content={"status": "ok"})
@stub.function(image=image) @asgi_app() def fastapi_app(): return web_app
If you don’t like adding the Python script inline in the YAML file, you can enable namespaceFiles
and add the Python code in the embedded Code Editor in a separate file e.g. called slack.py
and reference it in the flow as shown below:
id: slack_appnamespace: prod
tasks: - id: modal_slack_app type: io.kestra.plugin.modal.cli.ModalCLI namespaceFiles: enabled: true commands: - modal deploy slack.py env: MODAL_TOKEN_ID: "{{ secret('MODAL_TOKEN_ID') }}" MODAL_TOKEN_SECRET: "{{ secret('MODAL_TOKEN_SECRET') }}"
Once you execute that flow, you will see the endpoint to your app in the logs:
Go back to Slack and add the URL to the “Request URL” field in the “Event Subscriptions” section. Make sure to add slack/events
at the end of the URL, e.g.:
https://anna-geller--slack-app-fastapi-app.modal.run/slack/events
You should see the Verified
message. Hit Save Changes
and you’re all set!
Install the Slack app to a Workspace and test it
First, we need to install the app to the workspace. Go to “Install App” and click on “Install to Workspace”:
Now you can test the integration by mentioning your app in a channel. For example, you can write a hello message hello @kestra
:
Confirm to invite the app to the channel and congratulate yourself with the “Nicely done!” emoji 🙌:
You should see that both events (app mention
and reaction added
) have triggered an execution of your Kestra flow:
Now it’s up to you to automate your daily operations with Slack and Kestra!
Example automation: AI Chatbot
You can extend the slack_events
flow to automate your daily business operations.
To do something more useful than just logging the Slack event, you can create a flow that listens to the app_mention
event and responds to that message with a GPT-4 chatbot. First, create an incoming webhook in your Slack app:
Copy the webhook URL:
…and paste it into the url
field of the SlackIncomingWebhook
task in the flow below:
id: slack_eventsnamespace: prod
tasks: - id: if_app_mention type: io.kestra.plugin.core.flow.If condition: "{{ trigger.body.event.type == 'app_mention' }}" then: - id: gpt type: io.kestra.plugin.openai.ChatCompletion apiKey: "{{ secret('OPENAI_API_KEY') }}" model: gpt-4-0125-preview messages: - role: system content: The user will refer to you as <@{{ trigger.body.authorizations[0].user_id }}>. You get a prompt from a user and provide a concise answer. prompt: "{{ trigger.body.event.text ?? null }}"
- id: slack type: io.kestra.plugin.notifications.slack.SlackIncomingWebhook url: "{{ secret('SLACK_WEBHOOK_URL') }}" payload: | {"channel":"{{ trigger.body.event.channel }}","text":"{{ outputs.gpt.choices[0].message.content }}"} else: - id: other_events type: io.kestra.plugin.core.log.Log message: "{{ trigger.body }}"
triggers: - id: slack_event type: io.kestra.plugin.core.trigger.Webhook key: superStrongSecretKey42
Note that the SlackIncomingWebhook
task also has the messageText
property that can be used instead of the payload
property, depending on the task’s requirements.
And here is the result:
Local testing with ngrok
If you don’t want to host your app on Modal, you can use ngrok to expose your local server to the internet.
First, install ngrok:
brew install ngrok/ngrok/ngrok
Then, sign up for a free account and then authenticate your terminal, as explained in the Getting Started guide:
ngrok config add-authtoken long_token_string
Create a FastAPI app in a file called main.py
:
from fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponseimport requests
app = FastAPI()
@app.post("/slack/events")async def slack_events(request: Request): json_data = await request.json()
# Slack URL Verification Challenge if "challenge" in json_data: return JSONResponse(content={"challenge": json_data["challenge"]})
print("Received an event") print(json_data)
# URL of your Kestra flow webhook url = "http://your_kestra_host:8080/api/v1/main/executions/webhook/prod/slack_events/superStrongSecretKey42" headers = { "Content-Type": "application/json", }
response = requests.post(url, headers=headers, json=json_data) print(response.text)
return JSONResponse( content={"status": response.status_code, "response": response.text} )
Then, set up your FastAPI server:
pip install fastapi uvicorn requestsuvicorn main:app --reload --port 3000ngrok http http://localhost:3000
This will expose your local server to the internet. You should see a similar URL:
https://0913-31-18-152-123.ngrok-free.app
Go back to your Slack app and add the URL to the “Request URL” field in the “Event Subscriptions” section. Make sure to add slack/events
at the end of the URL, e.g.:
https://0913-31-18-152-123.ngrok-free.app/slack/events
The rest of the process is the same as with Modal. You can now adjust the flow slack_events
referenced in the FastAPI code and start automationg various processes based on Slack events.
Other deployment options
You can deploy that Slack app in many other ways including:
- an on-prem VM
- a serverless approach with AWS Lambda, Google Cloud Functions, or Azure Functions
- a containerized approach with AWS Fargate, Google Cloud Run, or Azure Container Instances
- a Kubernetes deployment.
And of course, you can use any other programming language and framework to build your Slack app. The only requirement is to forward the Slack events to your Kestra flow via the Webhook trigger.