Triggers

Triggers monitor specific events in apps and notify your AI agents via webhooks or websockets. They send in relevant data that your agents can act upon.

Use gpt-4.5 to reply in greentexts to Slack messages.

Make sure you’ve created an integration and a connection to your Slack account.

Managing Integrations

Learn how to manage integrations and connected accounts.

Managing triggers

1

Enable the Trigger

Enable the “New Message Received” trigger for your Slack app through the dashboard, CLI, or code.

2

Configure Webhook URL

Set up a publicly accessible URL where Composio can send event payloads.

3

Implement Handler

Create a webhook handler to process incoming Slack messages.

Head to the Slack app in the dashboard and enable the “New Message Recieved” trigger

Specifying Trigger Configuration

Some triggers expect certain configuration in order to set the correct events. You can inspect and add these properties while enabling the triggers!

Viewing the expected configuration
1trigger = toolset.get_trigger("GITHUB_STAR_ADDED_EVENT")
2print(trigger.config.model_dump_json(indent=4))
Expected properties
1{
2 "properties": {
3 "owner": {
4 "description": "Owner of the repository",
5 "title": "Owner",
6 "default": null,
7 "type": "string"
8 },
9 "repo": {
10 "description": "Repository name",
11 "title": "Repo",
12 "default": null,
13 "type": "string"
14 }
15 },
16 "title": "WebhookConfigSchema",
17 "type": "object",
18 "required": [
19 "owner",
20 "repo"
21 ]
22}
Specifying the configuration
1response = entity.enable_trigger(
2 app=App.GITHUB,
3 trigger_name="GITHUB_PULL_REQUEST_EVENT",
4 config={"owner": "composiohq", "repo": "composio"},
5)

Listeners

Once you have the triggers set up, you can specify listener functions using websockets through the SDK or webhooks.

Specifying Listeners through Websockets

We create a listener and then define a callback function that executes when a listener recieves a payload.

Creating a listener and defining a callback
1from composio_openai import ComposioToolSet, App, Action
2
3toolset = ComposioToolSet()
4entity = toolset.get_entity(id="default")
5
6listener = toolset.create_trigger_listener()
7@listener.callback(
8 filters={
9 "trigger_name": "SLACK_RECEIVE_MESSAGE",
10 }
11)
12def handle_slack_message(event):
13 print(event)
14
15listener.wait_forever()

Specifying Listeners through Webhooks

Assuming you’ve already set up a trigger as discussed in previous steps, here’s how you can use webhooks instead to listen in on new events happening in an app.

1

Configure Webhook URL

To receive trigger events via webhooks, you need to configure a publicly accessible URL where Composio can send the event payloads. This URL should point to an endpoint in your application that can process incoming webhook requests.

2

Listening on the webhooks

To demonstrate, here’s a FastAPI server to handle incoming webhook requests.

1from fastapi import FastAPI, Request
2from typing import Dict, Any
3import uvicorn
4import json
5
6app = FastAPI(title="Webhook Demo")
7
8@app.post("/webhook")
9async def webhook_handler(request: Request):
10 # Get the raw payload
11 payload = await request.json()
12
13 # Log the received webhook data
14 print("Received webhook payload:")
15 print(json.dumps(payload, indent=2))
16
17 # Return a success response
18 return {"status": "success", "message": "Webhook received"}
19
20if __name__ == "__main__":
21 uvicorn.run(app, host="0.0.0.0", port=8000)
To test out webhooks locally, use an SSH tunnel like ngrok

Demo: Roast Slack Messages

Let’s build a fun bot that generates snarky greentext responses to Slack messages using gpt-4.5.

1

Set up the FastAPI Server

First, let’s create a FastAPI server to handle webhook events:

1from fastapi import FastAPI, Request
2from openai import OpenAI
3from composio_openai import ComposioToolSet, App, Action
4from dotenv import load_dotenv
5import uvicorn
6
7load_dotenv()
8app = FastAPI()
9client = OpenAI()
10toolset = ComposioToolSet()
11entity = toolset.get_entity(id="default")
2

Track Responded Threads

Create a set to avoid duplicate responses:

1# Set to keep track of threads we've already responded to
2responded_threads = set()
3

Implement Response Generation

Create a function to generate snarky responses using gpt-4.5. We’ll also set up a preprocessor to handle Slack-specific message parameters:

1async def generate_response(payload: Dict[str, Any]):
2 ts = payload.get("data", {}).get("ts", "")
3 thread_ts = payload.get("data", {}).get("thread_ts", ts)
4 channel = payload.get("data", {}).get("channel", "")
5
6 # Skip if already responded
7 if thread_ts in responded_threads:
8 return
9
10 responded_threads.add(thread_ts)
11
12 # Preprocessor to automatically inject Slack-specific parameters
13 def slack_send_message_preprocessor(inputs: Dict[str, Any]) -> Dict[str, Any]:
14 inputs["thread_ts"] = ts # Ensure reply goes to the correct thread
15 inputs["channel"] = channel # Target the specific channel
16 inputs["mrkdwn"] = False # Disable markdown for greentext formatting
17 return inputs
4

Configure the tools

Set up the tools for sending Slack messages. We attach our preprocessor to automatically handle message threading and formatting:

1# Configure tools with the preprocessor to handle Slack-specific parameters
2tools = toolset.get_tools(
3 [Action.SLACK_SENDS_A_MESSAGE_TO_A_SLACK_CHANNEL],
4 processors={
5 "pre": {
6 Action.SLACK_SENDS_A_MESSAGE_TO_A_SLACK_CHANNEL: slack_send_message_preprocessor
7 }
8 }
9)
10
11response = client.chat.completions.create(
12 model="gpt-4.5-preview",
13 messages=[
14 {"role": "system", "content": "Given a slack text. Generate a snarky greentext response mocking the user. Render the response in ``` codeblocks"},
15 {"role": "user", "content": payload.get("data", {}).get("text")}
16 ],
17 tools=tools,
18 tool_choice="required"
19)
20toolset.handle_tool_calls(response, entity_id="default")

The preprocessor ensures that every message is automatically configured with the correct thread, channel, and formatting settings, reducing the chance of misconfigured responses.

5

Create Webhook Handler

Set up the webhook endpoint to process incoming messages:

1@app.post("/webhook")
2async def webhook_handler(request: Request):
3 payload = await request.json()
4 if payload.get("type") == "slack_receive_message":
5 channel = payload.get("data", {}).get("channel")
6 if channel == "YOUR_CHANNEL_ID": # Replace with your channel ID
7 await generate_response(payload)
8 return {"status": "success", "message": "Webhook received"}
9
10uvicorn.run(app, host="0.0.0.0", port=8000)
Testing Locally

Run your server locally and use ngrok to expose it:

$# Start your FastAPI server
>python webhook.py
>
># In another terminal, start ngrok
>ngrok http 8000

Remember to update your webhook URL in the Composio dashboard with your ngrok URL.

Troubleshooting

If you encounter issues with triggers or webhook listeners, you can use the Composio dashboard to inspect detailed trigger logs. The dashboard allows you to review event payloads, identify errors, and manually resend events for testing purposes.

Access the trigger logs here

Built with