Initial push of Plunk Next
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
---
|
||||
title: Workflows
|
||||
description: Automate email sequences with triggers and conditions
|
||||
---
|
||||
|
||||
## What are workflows
|
||||
|
||||
Workflows automate email sequences based on user behavior. Build onboarding drips, re-engagement campaigns, and event-triggered emails—all without writing code.
|
||||
|
||||
A workflow consists of:
|
||||
- **Trigger** — What starts the workflow (event, segment entry, schedule)
|
||||
- **Steps** — Actions like sending emails, waiting, or checking conditions
|
||||
- **Transitions** — Connections between steps that define the flow
|
||||
|
||||
## Common use cases
|
||||
|
||||
### Welcome series
|
||||
|
||||
Send a 3-email onboarding sequence when users sign up:
|
||||
|
||||
1. User triggers `signed_up` event
|
||||
2. Send welcome email immediately
|
||||
3. Wait 1 day
|
||||
4. Send getting started guide
|
||||
5. Wait 2 days
|
||||
6. Send feature tips
|
||||
|
||||
### Abandoned cart recovery
|
||||
|
||||
Re-engage users who add items but don't purchase:
|
||||
|
||||
1. User triggers `cart_abandoned` event
|
||||
2. Wait 1 hour
|
||||
3. Send reminder email with cart contents
|
||||
4. Wait for `purchase` event (timeout: 24 hours)
|
||||
5. If purchased → Exit workflow
|
||||
6. If timeout → Send discount offer
|
||||
|
||||
### Trial expiration
|
||||
|
||||
Notify users before trial ends and encourage upgrade:
|
||||
|
||||
1. Trigger daily at 9am
|
||||
2. Check if trial expires in 3 days
|
||||
3. If yes → Send upgrade reminder
|
||||
4. Wait for `subscription_created` event (timeout: 3 days)
|
||||
5. If subscribed → Send thank you email
|
||||
6. If timeout → Send last chance offer
|
||||
|
||||
### Re-engagement campaign
|
||||
|
||||
Win back inactive users:
|
||||
|
||||
1. Contact enters "Inactive Users" segment
|
||||
2. Send "We miss you" email
|
||||
3. Wait for `login` event (timeout: 7 days)
|
||||
4. If logged in → Exit workflow
|
||||
5. If timeout → Send special offer
|
||||
|
||||
## Creating workflows
|
||||
|
||||
### In the dashboard
|
||||
|
||||
1. Go to **Workflows**
|
||||
2. Click **Create Workflow**
|
||||
3. Name your workflow
|
||||
4. Choose trigger type
|
||||
5. Add steps using visual builder
|
||||
6. Connect steps with transitions
|
||||
7. Activate workflow
|
||||
|
||||
### Via API
|
||||
|
||||
```bash
|
||||
curl -X POST {{API_URL}}/workflows \
|
||||
-H "Authorization: Bearer sk_your_secret_key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Welcome Series",
|
||||
"eventName": "signed_up",
|
||||
"enabled": true
|
||||
}'
|
||||
```
|
||||
|
||||
Then add steps and transitions through the dashboard or API.
|
||||
|
||||
## Trigger types
|
||||
|
||||
### Event trigger
|
||||
|
||||
Starts when a specific event is tracked:
|
||||
|
||||
```json
|
||||
{
|
||||
"triggerType": "EVENT",
|
||||
"triggerConfig": {
|
||||
"eventName": "signed_up"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Track the event with `/v1/track` to start the workflow.
|
||||
|
||||
### Segment entry
|
||||
|
||||
Starts when contact joins a segment:
|
||||
|
||||
```json
|
||||
{
|
||||
"triggerType": "SEGMENT_ENTRY",
|
||||
"triggerConfig": {
|
||||
"segmentId": "premium-users"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Requires segment to have `trackMembership: true`.
|
||||
|
||||
### Segment exit
|
||||
|
||||
Starts when contact leaves a segment:
|
||||
|
||||
```json
|
||||
{
|
||||
"triggerType": "SEGMENT_EXIT",
|
||||
"triggerConfig": {
|
||||
"segmentId": "trial-users"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schedule
|
||||
|
||||
Runs on a cron schedule:
|
||||
|
||||
```json
|
||||
{
|
||||
"triggerType": "SCHEDULE",
|
||||
"triggerConfig": {
|
||||
"schedule": "0 9 * * *"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Evaluates all contacts—use conditions to filter who continues.
|
||||
|
||||
## Workflow steps
|
||||
|
||||
### Send Email
|
||||
|
||||
Send a template to the contact:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "SEND_EMAIL",
|
||||
"config": {
|
||||
"templateId": "welcome-template"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Delay
|
||||
|
||||
Wait before continuing:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "DELAY",
|
||||
"config": {
|
||||
"duration": 86400,
|
||||
"unit": "seconds"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Common durations:
|
||||
- 1 hour: `3600`
|
||||
- 1 day: `86400`
|
||||
- 1 week: `604800`
|
||||
|
||||
### Wait for Event
|
||||
|
||||
Pause until an event occurs or timeout:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "WAIT_FOR_EVENT",
|
||||
"config": {
|
||||
"eventName": "purchase",
|
||||
"timeout": 604800
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create two transitions: one for "success" (event occurred) and one for "timeout".
|
||||
|
||||
### Condition
|
||||
|
||||
Branch based on contact data:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "CONDITION",
|
||||
"config": {
|
||||
"field": "data.plan",
|
||||
"operator": "equals",
|
||||
"value": "premium"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create two transitions: "true" and "false".
|
||||
|
||||
### Update Contact
|
||||
|
||||
Modify contact fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "UPDATE_CONTACT",
|
||||
"config": {
|
||||
"data": {
|
||||
"onboardingCompleted": true,
|
||||
"completedAt": "{{now}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Webhook
|
||||
|
||||
Call an external API:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "WEBHOOK",
|
||||
"config": {
|
||||
"url": "https://api.example.com/webhook",
|
||||
"method": "POST",
|
||||
"body": {
|
||||
"email": "{{email}}",
|
||||
"event": "workflow_completed"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exit
|
||||
|
||||
End the workflow:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "EXIT"
|
||||
}
|
||||
```
|
||||
|
||||
## Re-entry behavior
|
||||
|
||||
Control whether contacts can enter a workflow multiple times:
|
||||
|
||||
### Prevent re-entry (default)
|
||||
|
||||
**allowReentry: false**
|
||||
- Contact can only enter once, ever
|
||||
- Subsequent triggers are ignored
|
||||
- Use for one-time journeys
|
||||
|
||||
**Best for:**
|
||||
- User onboarding sequences
|
||||
- Welcome series
|
||||
- Trial expiration flows
|
||||
- One-time educational content
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"name": "Onboarding Series",
|
||||
"eventName": "user_signed_up",
|
||||
"allowReentry": false,
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
Even if the `user_signed_up` event fires multiple times for the same contact, they'll only enter once.
|
||||
|
||||
### Allow re-entry
|
||||
|
||||
**allowReentry: true**
|
||||
- Contact can enter multiple times
|
||||
- Each trigger starts a new execution
|
||||
- Multiple executions can run simultaneously
|
||||
|
||||
**Best for:**
|
||||
- Recurring events (weekly newsletters, monthly reports)
|
||||
- Behavior-triggered campaigns (cart abandonment, content engagement)
|
||||
- Event-specific sequences (order confirmations, webinar reminders)
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"name": "Cart Abandoned Reminder",
|
||||
"eventName": "cart_abandoned",
|
||||
"allowReentry": true,
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
User abandons cart multiple times → Each triggers a new workflow execution.
|
||||
|
||||
## Execution context
|
||||
|
||||
Pass event-specific data when workflows are triggered automatically.
|
||||
|
||||
### What is context?
|
||||
|
||||
Context is temporary data passed with a workflow execution that's available in templates but not saved to the contact record.
|
||||
|
||||
**Contact data vs Context:**
|
||||
- **Contact data** — Persistent, saved to contact, used for segmentation
|
||||
- **Execution context** — Temporary, specific to this workflow run, not saved
|
||||
|
||||
### Using context in templates
|
||||
|
||||
Context data is available in workflow email templates alongside contact data:
|
||||
|
||||
```html
|
||||
<h1>Hi {{firstName}}!</h1>
|
||||
<p>Order #{{orderNumber}} confirmed!</p>
|
||||
<p>Total: ${{orderTotal}}</p>
|
||||
<p>Tracking: <a href="{{trackingUrl}}">View shipment</a></p>
|
||||
```
|
||||
|
||||
Where:
|
||||
- `{{firstName}}` comes from contact.data
|
||||
- `{{orderNumber}}`, `{{orderTotal}}`, `{{trackingUrl}}` come from execution context
|
||||
|
||||
### Common patterns
|
||||
|
||||
**Order confirmations:**
|
||||
```javascript
|
||||
// Event includes order details
|
||||
{
|
||||
event: 'purchase_completed',
|
||||
email: '[email protected]',
|
||||
data: {
|
||||
// Saved to contact
|
||||
totalPurchases: 5,
|
||||
lifetimeValue: 599
|
||||
}
|
||||
}
|
||||
|
||||
// Workflow execution receives context (not saved)
|
||||
context: {
|
||||
orderNumber: 'ORD-12345',
|
||||
orderTotal: 99.99,
|
||||
trackingUrl: 'https://track.example.com/12345',
|
||||
deliveryDate: '2025-12-05'
|
||||
}
|
||||
```
|
||||
|
||||
**Event registrations:**
|
||||
```javascript
|
||||
context: {
|
||||
eventTitle: 'Email Marketing Workshop',
|
||||
eventDate: '2025-12-10T14:00:00Z',
|
||||
eventUrl: 'https://zoom.us/j/123456',
|
||||
speakerName: 'Jane Doe'
|
||||
}
|
||||
```
|
||||
|
||||
**Cart abandonment:**
|
||||
```javascript
|
||||
context: {
|
||||
cartTotal: 149.99,
|
||||
cartUrl: 'https://app.example.com/cart/abc123',
|
||||
itemCount: 3,
|
||||
expiresAt: '2025-12-01T10:00:00Z'
|
||||
}
|
||||
```
|
||||
|
||||
## Workflow execution
|
||||
|
||||
When a workflow triggers:
|
||||
|
||||
1. Contact enters at the trigger step
|
||||
2. Executes each step in sequence
|
||||
3. Follows transitions between steps
|
||||
4. Continues until reaching Exit step
|
||||
5. Status changes from RUNNING to COMPLETED
|
||||
|
||||
If contact unsubscribes or is deleted, workflow execution stops immediately.
|
||||
|
||||
## Managing workflows
|
||||
|
||||
### List workflows
|
||||
|
||||
```bash
|
||||
curl -X GET {{API_URL}}/workflows \
|
||||
-H "Authorization: Bearer sk_your_secret_key"
|
||||
```
|
||||
|
||||
### Get workflow details
|
||||
|
||||
```bash
|
||||
curl -X GET {{API_URL}}/workflows/workflow_id \
|
||||
-H "Authorization: Bearer sk_your_secret_key"
|
||||
```
|
||||
|
||||
### Activate/deactivate
|
||||
|
||||
```bash
|
||||
curl -X PATCH {{API_URL}}/workflows/workflow_id \
|
||||
-H "Authorization: Bearer sk_your_secret_key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"enabled": true}'
|
||||
```
|
||||
|
||||
### View executions
|
||||
|
||||
```bash
|
||||
curl -X GET "{{API_URL}}/workflows/workflow_id/executions" \
|
||||
-H "Authorization: Bearer sk_your_secret_key"
|
||||
```
|
||||
|
||||
## Best practices
|
||||
|
||||
**Start simple** — Begin with 2-3 emails before adding complex conditions.
|
||||
|
||||
**Test with yourself** — Create a test contact and trigger the workflow to verify timing and content.
|
||||
|
||||
**Monitor execution stats** — Check completion rates to identify where contacts drop off.
|
||||
|
||||
**Use meaningful names** — Name steps clearly: "Send Welcome Email" not "Step 1".
|
||||
|
||||
**Set appropriate timeouts** — For "Wait for Event" steps, choose realistic timeouts based on user behavior.
|
||||
|
||||
**Handle both paths** — Every condition and wait should have both success and failure paths defined.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Track events](/guides/events) to trigger workflows
|
||||
- [Create segments](/guides/segments) for segment-based triggers
|
||||
- [Build templates](/guides/templates) to use in workflow emails
|
||||
- [Set up webhooks](/guides/webhooks) for external integrations
|
||||
Reference in New Issue
Block a user