Triggers & Actions
Every automation has two parts: something that starts it (the trigger) and something that happens because of it (the action). Master this pattern and you can automate anything.
The Trigger-Action Pattern
Every automation in the world — from a Gmail filter to a million-dollar enterprise workflow — follows one pattern:
The trigger is the "when" — the event that starts the automation. The payload is the data that flows from trigger to action. The action is the "then" — what your automation does with that data.
Three Types of Triggers
Fires instantly when an external system sends data to your URL. Real-time — zero delay. Example: Stripe sends a webhook when a payment succeeds, your automation creates the customer account.
Fires on a time-based schedule — every hour, every day at 9 AM, every Monday. Uses cron expressions under the hood. Example: Every morning at 8 AM, pull yesterday's sales data and email a summary to the team.
Fires when something happens inside your own system — a database row changes, a user signs up, a file is uploaded. Example: When a new user signs up, send a welcome email and create their onboarding checklist.
Understanding Payloads
The payload is the data that flows from trigger to action. Every trigger produces a payload — it is what the action works with. Here is what a real webhook payload looks like:
{
"type": "payment_intent.succeeded",
"data": {
"customer_email": "jane@acme.co",
"amount": 4900,
"currency": "usd"
}
}
Your action reads this payload and acts on it — save the customer to a database, send a receipt email, update a dashboard. The payload is the bridge between trigger and action.
Here is how you set up a webhook listener in Python that receives that Stripe payload and routes it to the correct action:
from flask import Flask, request, jsonify
app = Flask(__name__)
# Define which action runs for each trigger event type
ACTIONS = {
"payment_intent.succeeded": "create_account",
"customer.subscription.deleted": "revoke_access",
"invoice.payment_failed": "send_retry_email",
}
@app.route("/webhook/stripe", methods=["POST"])
def stripe_webhook():
# The payload arrives as JSON in the request body
payload = request.get_json()
event_type = payload.get("type", "unknown")
# Route to the correct action based on trigger type
action = ACTIONS.get(event_type)
if action:
print(f"Trigger: {event_type} → Action: {action}")
dispatch_action(action, payload["data"])
else:
print(f"Unhandled event: {event_type}")
return jsonify({"received": True}), 200
def dispatch_action(action: str, data: dict):
"""Execute the action with the trigger's payload data."""
if action == "create_account":
email = data["customer_email"]
print(f"Creating account for {email}")
elif action == "revoke_access":
print(f"Revoking access for {data['customer_email']}")
elif action == "send_retry_email":
print(f"Sending payment retry email to {data['customer_email']}")
Real-World Automation Examples
When Things Go Wrong
Real automations fail. Knowing the failure modes makes you a better architect:
Trigger Design Patterns
Beyond the three trigger types, there are four design patterns that determine how triggers behave in production. Understanding these patterns helps you choose the right approach for reliability, latency, and resource usage.
Your system checks for new data at regular intervals using a cron schedule. Simple but introduces delay — if you poll every 5 minutes, events can wait up to 5 minutes before processing. Best for batch operations where real-time is not critical: daily reports, hourly data sync, nightly cleanup jobs.
Your system reacts to events as they happen within your own infrastructure. A database trigger fires when a row changes. A message queue consumer processes events as they arrive. Zero delay, no wasted resources. Best for internal system events: user signups, order status changes, inventory updates.
A monitor watches a metric and fires when it crosses a threshold. CPU usage exceeds 90%. Revenue drops below a target. Error rate spikes above 5%. The trigger is not a single event but a state change — something crossed a line. Best for alerting, auto-scaling, and business rules.
An external service sends an HTTP POST to your URL when something happens in their system. Stripe sends a webhook when a payment succeeds. GitHub sends one when code is pushed. You do not poll — the external system tells you. Real-time with no wasted requests. Best for third-party integrations.