Your First Real Workflow
Build a workflow that responds to webhooks and sends notifications
Your First Real Workflow
In this tutorial, you'll build a real-world workflow that:
- Triggers when a Stripe payment is received
- Transforms the payment data
- Sends a Slack notification
Prerequisites
- Completed the Quickstart
- A Slack workspace (for notifications)
- Optional: Stripe account (for live testing)
What We're Building
graph LR
A[Stripe Webhook] --> B[Transform Data]
B --> C[Send Slack Message]When a payment is received in Stripe, the workflow will send a message to your Slack channel with payment details.
Step 1: Create the Workflow
Create a workflow with a webhook trigger:
curl -X POST http://localhost:3000/api/v1/workflows \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Payment Notification",
"description": "Send Slack notification when payment received",
"trigger": {
"type": "webhook",
"provider": "stripe",
"events": ["payment_intent.succeeded", "charge.succeeded"]
},
"steps": [
{
"id": "transform-payment",
"type": "transform",
"name": "Format Payment Data",
"config": {
"mapping": {
"amount": "{{input.data.object.amount}}",
"currency": "{{input.data.object.currency}}",
"customer_email": "{{input.data.object.receipt_email}}",
"payment_id": "{{input.data.object.id}}",
"formatted_amount": "${{input.data.object.amount / 100}}"
}
}
},
{
"id": "notify-slack",
"type": "slack",
"name": "Send Slack Notification",
"config": {
"action": "sendMessage",
"channel": "#payments",
"text": "Payment received! {{steps.transform-payment.output.formatted_amount}} from {{steps.transform-payment.output.customer_email}}"
}
}
]
}'const workflow = {
name: 'Payment Notification',
description: 'Send Slack notification when payment received',
trigger: {
type: 'webhook',
provider: 'stripe',
events: ['payment_intent.succeeded', 'charge.succeeded']
},
steps: [
{
id: 'transform-payment',
type: 'transform',
name: 'Format Payment Data',
config: {
mapping: {
amount: '{{input.data.object.amount}}',
currency: '{{input.data.object.currency}}',
customer_email: '{{input.data.object.receipt_email}}',
payment_id: '{{input.data.object.id}}',
formatted_amount: '${{input.data.object.amount / 100}}'
}
}
},
{
id: 'notify-slack',
type: 'slack',
name: 'Send Slack Notification',
config: {
action: 'sendMessage',
channel: '#payments',
text: 'Payment received! {{steps.transform-payment.output.formatted_amount}} from {{steps.transform-payment.output.customer_email}}'
}
}
]
};
const response = await fetch('http://localhost:3000/api/v1/workflows', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(workflow)
});
const { data } = await response.json();
console.log('Workflow ID:', data.id);Save the workflow ID from the response.
Step 2: Connect Slack
Before activating, connect your Slack workspace:
# Get the OAuth URL for Slack
curl "http://localhost:3000/api/v1/connections/slack/auth-url" \
-H "x-api-key: YOUR_API_KEY"This returns a URL to complete the Slack OAuth flow:
{
"success": true,
"data": {
"url": "https://slack.com/oauth/v2/authorize?client_id=..."
}
}Visit the URL, authorize your workspace, and you'll be redirected back.
Step 3: Activate the Workflow
curl -X POST http://localhost:3000/api/v1/workflows/{WORKFLOW_ID}/activate \
-H "x-api-key: YOUR_API_KEY"Step 4: Configure Stripe Webhook
Add your webhook URL to Stripe's dashboard:
https://your-domain.com/webhooks/stripe/{COMPANY_ID}Or for local development with a tunnel like ngrok:
https://your-ngrok-id.ngrok.io/webhooks/stripe/{COMPANY_ID}Select the events:
payment_intent.succeededcharge.succeeded
Step 5: Test the Workflow
You can test without Stripe by manually triggering the workflow:
curl -X POST http://localhost:3000/api/v1/workflows/{WORKFLOW_ID}/run \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_test123",
"amount": 9900,
"currency": "usd",
"receipt_email": "customer@example.com"
}
}
}
}'You should see a message in your #payments Slack channel!
Understanding the Workflow
Trigger Configuration
{
"type": "webhook",
"provider": "stripe",
"events": ["payment_intent.succeeded", "charge.succeeded"]
}type: "webhook"- Triggered by incoming webhooksprovider: "stripe"- Expects Stripe webhook format and signature verificationevents- Only trigger on these specific event types
Template Variables
The workflow uses template variables to access data:
| Variable | Description |
|---|---|
{{input.*}} | Access webhook payload data |
{{steps.{id}.output.*}} | Access output from previous steps |
{{now}} | Current timestamp |
Transform Step
{
"type": "transform",
"config": {
"mapping": {
"formatted_amount": "${{input.data.object.amount / 100}}"
}
}
}The transform step maps input data to a new structure. You can:
- Rename fields
- Compute values (like dividing cents by 100)
- Combine fields
Slack Step
{
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#payments",
"text": "..."
}
}The Slack building block supports:
sendMessage- Send to channel or DMsendEphemeral- Visible to one user onlyaddReaction- Add emoji reaction- And more (see Slack Block docs)
Adding Conditional Logic
Let's enhance the workflow to only notify for payments over $100:
{
"steps": [
{
"id": "transform-payment",
"type": "transform",
"config": {
"mapping": {
"amount_dollars": "{{input.data.object.amount / 100}}",
"customer_email": "{{input.data.object.receipt_email}}"
}
}
},
{
"id": "check-amount",
"type": "condition",
"name": "Check if High Value",
"config": {
"conditions": {
"left": "{{steps.transform-payment.output.amount_dollars}}",
"operator": "gte",
"right": "100"
},
"then": ["notify-slack"],
"else": []
}
},
{
"id": "notify-slack",
"type": "slack",
"config": {
"action": "sendMessage",
"channel": "#high-value-payments",
"text": "High value payment: ${{steps.transform-payment.output.amount_dollars}} from {{steps.transform-payment.output.customer_email}}"
}
}
]
}Viewing Run History
Check workflow run history:
curl "http://localhost:3000/api/v1/workflows/{WORKFLOW_ID}/runs" \
-H "x-api-key: YOUR_API_KEY"Get details for a specific run:
curl "http://localhost:3000/api/v1/runs/{RUN_ID}" \
-H "x-api-key: YOUR_API_KEY"The response shows each step's status, timing, and output:
{
"success": true,
"data": {
"id": "run_xyz...",
"status": "completed",
"steps": [
{
"id": "transform-payment",
"status": "completed",
"output": {
"amount_dollars": 99,
"customer_email": "customer@example.com"
}
},
{
"id": "notify-slack",
"status": "completed",
"output": {
"ts": "1234567890.123456",
"channel": "C123ABC"
}
}
]
}
}