---
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: 'user@example.com',
  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
