# Building Workflows

Source: https://wraps.dev/docs/guides/workflows

Define automated email and SMS sequences as code using a declarative DSL. Build drip campaigns, onboarding sequences, and re-engagement flows that run on the Wraps Platform.

## Defining a Workflow

A workflow is a sequence of steps triggered by an event. Each workflow is defined in a TypeScript file using the `defineWorkflow` helper and exported as the default export.

wraps/workflows/welcome-sequence.ts

```
// wraps/workflows/welcome-sequence.tsimport {  defineWorkflow,  sendEmail,  delay,  condition,  exit,  waitForEvent,} from '@wraps.dev/client';export default defineWorkflow({  name: 'Welcome Sequence',  trigger: {    type: 'contact.created',  },  settings: {    maxEnrollments: 1, // Each contact enters once  },  steps: [    sendEmail('welcome', { template: 'welcome-email' }),    delay('wait-1-day', { days: 1 }),    condition('check-activated', {      field: 'contact.hasActivated',      operator: 'equals',      value: true,      branches: {        yes: [exit('already-active')],        no: [          sendEmail('activation-reminder', { template: 'activate' }),          delay('wait-2-days', { days: 2 }),          sendEmail('final-reminder', { template: 'last-chance' }),        ],      },    }),  ],});
```

Type-safe workflow definitions

All step helpers are fully typed. Your editor provides autocompletion for configuration options, trigger types, and operator values.

## Trigger Types

Triggers determine when a contact enters a workflow. Each workflow has exactly one trigger.

| Type | Description |
| --- | --- |
| `contact.created` | When a new contact is added |
| `contact.updated` | When contact fields change |
| `event.received` | When a custom event is received |
| `segment.entered` | When a contact enters a segment |
| `segment.exited` | When a contact exits a segment |
| `manual` | Manually triggered via API |

## Step Helpers

Wraps provides 11 step helpers to build your workflow logic. Each helper takes a unique step ID and a configuration object.

1.`sendEmail(id, config)`

Send an email using a template.

Config: `template, from?, fromName?`

2.`sendSms(id, config)`

Send an SMS message.

Config: `template?, message?`

3.`delay(id, duration)`

Wait before continuing.

Config: `{ days?, hours?, minutes? }`

4.`condition(id, config)`

Branch based on a condition.

Config: `field, operator, value, branches: { yes: [...], no: [...] }`

5.`waitForEvent(id, config)`

Pause until an event occurs.

Config: `eventName, timeout?`

6.`waitForEmailEngagement(id, config)`

Wait for email open or click.

Config: `emailStepId, engagementType ('opened' | 'clicked'), timeout?`

7.`exit(id, config?)`

End the workflow.

Config: `reason?, markAs? ('completed' | 'cancelled')`

8.`updateContact(id, config)`

Modify contact fields.

Config: `updates: [{ field, operation: 'set' | 'increment' | 'append', value }]`

9.`subscribeTopic(id, config)`

Subscribe contact to a topic.

Config: `topicId, channel ('email' | 'sms')`

10.`unsubscribeTopic(id, config)`

Unsubscribe contact from a topic.

Config: `topicId, channel ('email' | 'sms')`

11.`webhook(id, config)`

Call an external webhook.

Config: `url, method? ('POST' default), headers?, body?`

## Validate & Push

Before deploying, validate your workflow definitions to catch errors like missing templates, invalid step references, or circular dependencies. Then push to the Wraps Platform.

terminal.sh

```
# Validate workflow definitionswraps email workflows validate# Push to Wraps Platformwraps email workflows push
```

Validation checks:

-   All referenced templates exist in your templates directory
-   Step IDs are unique within each workflow
-   Condition branches reference valid step IDs
-   `waitForEmailEngagement` references a valid `sendEmail` step

## Example: Re-engagement Campaign

This workflow targets contacts who have been inactive for 30 days. It sends a win-back email, waits for engagement, and branches based on whether the contact opened it.

wraps/workflows/re-engagement.ts

```
import {  defineWorkflow,  sendEmail,  delay,  condition,  exit,  waitForEmailEngagement,} from '@wraps.dev/client';export default defineWorkflow({  name: 'Re-engagement Campaign',  trigger: {    type: 'segment.entered',    segmentId: 'inactive-30-days',  },  steps: [    sendEmail('win-back', { template: 'we-miss-you' }),    waitForEmailEngagement('check-opened', {      emailStepId: 'win-back',      engagementType: 'opened',      timeout: { days: 3 },    }),    condition('was-opened', {      field: 'steps.check-opened.engaged',      operator: 'equals',      value: true,      branches: {        yes: [          sendEmail('special-offer', { template: 'comeback-offer' }),          exit('re-engaged'),        ],        no: [          delay('wait-week', { days: 7 }),          sendEmail('final-attempt', { template: 'last-chance' }),          exit('campaign-complete'),        ],      },    }),  ],});
```

### How this workflow runs:

1.  Contact enters the `inactive-30-days` segment, triggering the workflow
2.  A "we miss you" email is sent immediately
3.  The workflow waits up to 3 days for the contact to open the email
4.  If opened: a special offer email is sent and the workflow ends
5.  If not opened: the workflow waits 7 more days, sends a final attempt, then ends

## Next Steps

Templates as Code

Write email templates as React components for use in workflows.

[Template Guide](https://wraps.dev/docs/guides/templates)

Preventing Duplicate Sends

Workflow steps deduplicate themselves. Sends from your own background workers do not — here is how to make them.

[Idempotency Guide](https://wraps.dev/docs/guides/idempotency)

Platform SDK

Full reference for the Wraps client SDK and workflow API.

[SDK Reference](https://wraps.dev/docs/client-sdk-reference)
