LoopFour

Workflow Overview

Core workflow concepts, lifecycle, and execution model

Workflow Overview

Workflows are the core building blocks of the Workflows API. This guide explains the fundamental concepts you need to understand when building automated processes.

What is a Workflow?

A workflow is a declarative automation that defines:

  1. When to run (the trigger)
  2. What to do (the steps)
  3. How to handle data (variables and templates)

Workflows enable you to:

  • Connect systems - Integrate Stripe, Salesforce, HubSpot, QuickBooks, and more
  • Transform data - Map and reshape data between different formats
  • Make decisions - Branch logic based on conditions
  • Wait for events - Pause for human approval or external events
  • Handle errors - Automatic retries with configurable strategies
graph LR
    A[Trigger] --> B[Step 1]
    B --> C[Step 2]
    C --> D{Condition}
    D -->|Yes| E[Step 3a]
    D -->|No| F[Step 3b]
    E --> G[Output]
    F --> G

Workflow Lifecycle

Every workflow progresses through a defined set of states:

stateDiagram-v2
    [*] --> draft: Create
    draft --> active: Activate
    active --> paused: Pause
    paused --> active: Resume
    active --> archived: Archive
    paused --> archived: Archive
    draft --> archived: Archive
StateDescriptionCan Execute?Can Edit?
draftInitial state after creationNoYes
activeReady to receive triggers and executeYesYes (creates new version)
pausedTemporarily disabledNoYes
archivedSoft deletedNoNo

State Transitions

curl -X POST http://localhost:3000/api/v1/workflows/{id}/activate \
  -H "x-api-key: YOUR_API_KEY"

Workflow Structure

A workflow is defined as a JSON object with these key components:

{
  "name": "Invoice on Deal Close",
  "description": "Create a QuickBooks invoice when a Salesforce deal is won",
 
  // 1. TRIGGER - When does this workflow run?
  "trigger": {
    "type": "webhook",
    "provider": "salesforce",
    "events": ["opportunity.closed_won"]
  },
 
  // 2. STEPS - What actions does it perform?
  "steps": [
    {
      "id": "transform-data",
      "type": "transform",
      "name": "Map Deal to Invoice",
      "config": {
        "mapping": {
          "customer_email": "{{input.account.email}}",
          "amount": "{{input.opportunity.amount}}",
          "description": "{{input.opportunity.name}}"
        }
      }
    },
    {
      "id": "create-invoice",
      "type": "action",
      "name": "Create QuickBooks Invoice",
      "config": {
        "connector": "quickbooks",
        "action": "createInvoice",
        "params": {
          "customerEmail": "{{steps.transform-data.output.customer_email}}",
          "amount": "{{steps.transform-data.output.amount}}",
          "memo": "{{steps.transform-data.output.description}}"
        }
      }
    }
  ],
 
  // 3. VARIABLES - Reusable configuration values
  "variables": {
    "taxRate": 0.0825,
    "defaultTerms": "Net 30"
  }
}

Triggers

Triggers define when a workflow executes. The Workflows API supports multiple trigger types:

TypeDescriptionUse Case
webhookExternal system sends an eventStripe payment, custom webhooks
scheduleTime-based executionDaily reports, weekly syncs
apiManual execution via APIOn-demand processing, testing
salesforce_eventSalesforce Platform Events or CDCRecord changes, custom events
hubspot_eventHubSpot property changesContact/deal updates
slack_eventSlack Events APIMessages, mentions, reactions
slack_slash_commandSlack slash commands/invoice, /approve
slack_interactiveSlack interactive componentsButton clicks, modal submissions
gmail_eventGmail Pub/Sub eventsNew emails, label changes

Webhook Triggers

Webhook triggers listen for events from external providers:

{
  "trigger": {
    "type": "webhook",
    "provider": "stripe",
    "events": ["invoice.paid", "invoice.payment_failed"]
  }
}

Supported providers: stripe, salesforce, hubspot, quickbooks, pandadoc, netsuite, slack

See Webhook Triggers for provider-specific configuration.

Schedule Triggers

Schedule triggers use cron expressions for time-based execution:

{
  "trigger": {
    "type": "schedule",
    "cron": "0 9 * * MON",
    "timezone": "America/New_York"
  }
}

See Schedule Triggers for cron syntax and examples.

API Triggers

API triggers allow manual workflow execution:

{
  "trigger": {
    "type": "api"
  }
}
curl -X POST http://localhost:3000/api/v1/workflows/{id}/run \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": {"customer_id": "cus_123"}}'

Steps

Steps define what a workflow does. Each step executes sequentially (unless using parallel execution).

Step Types

TypeDescriptionExample
actionCall an integrationCreate Stripe invoice, update Salesforce record
transformMap and reshape dataConvert webhook payload to invoice format
conditionBranch based on logicIf amount > $1000, require approval
waitPause executionWait 24 hours, delay before retry
parallelExecute steps concurrentlyNotify Slack AND send email
loopIterate over a collectionProcess each line item
approvalHuman-in-the-loopWait for manager approval
agentAI-powered processingExtract invoice data, classify expense
codeCustom JavaScriptRun sandboxed code for complex logic
slackSlack building blockSend message, open modal
emailEmail building blockSend templated email
gmailGmail building blockRead/send Gmail messages

Step Structure

Every step has this base structure:

{
  "id": "unique-step-id",
  "type": "action",
  "name": "Human-readable name",
  "action": "stripe.createInvoice",
  "config": {
    // Step-specific configuration
  },
  "retryConfig": {
    "maxAttempts": 3,
    "initialDelayMs": 1000,
    "maxDelayMs": 30000,
    "backoffMultiplier": 2
  },
  "errorHandling": {
    "strategy": "fail",
    "fallback": {}
  },
  "timeoutMs": 30000
}

See Steps Documentation for detailed configuration of each step type.

Template Variables

Template variables allow dynamic data access throughout your workflow using {{expression}} syntax.

Available Contexts

ContextSyntaxDescription
Input{{input.field}}Trigger payload data
Steps{{steps.stepId.output.field}}Previous step outputs
Variables{{variables.name}}Workflow-defined variables
Environment{{env.VAR_NAME}}Environment variables
System{{now}}, {{runId}}System-provided values

Examples

{
  "steps": [
    {
      "id": "send-email",
      "type": "action",
      "config": {
        "connector": "email",
        "action": "send",
        "params": {
          // Access trigger input
          "to": "{{input.customer.email}}",
 
          // Access previous step output
          "subject": "Invoice #{{steps.create-invoice.output.invoice_number}}",
 
          // Access workflow variables
          "cc": "{{variables.financeEmail}}",
 
          // Use expressions
          "body": "Amount due: ${{input.amount / 100}}"
        }
      }
    }
  ]
}

Nested Access

Access nested properties using dot notation:

{{input.customer.billing.address.city}}
{{steps.fetch-deal.output.opportunity.account.owner.email}}

Conditional Expressions

Use Handlebars-style conditionals in templates:

{{#if input.is_priority}}URGENT: {{/if}}New invoice created

Workflow Execution

When a workflow executes, it creates a run that tracks the execution state.

sequenceDiagram
    participant T as Trigger
    participant W as Workflow Engine
    participant S1 as Step 1
    participant S2 as Step 2
    participant DB as Database
 
    T->>W: Event received
    W->>DB: Create run (pending)
    W->>S1: Execute step
    S1-->>W: Output
    W->>DB: Update step status
    W->>S2: Execute step
    S2-->>W: Output
    W->>DB: Run completed

Run States

StateDescription
pendingRun created, waiting to start
runningCurrently executing steps
suspendedPaused for human approval or external event
completedAll steps finished successfully
failedA step failed after all retries
cancelledManually cancelled

Viewing Run History

# List runs for a workflow
curl "http://localhost:3000/api/v1/workflows/{id}/runs" \
  -H "x-api-key: YOUR_API_KEY"
 
# Get run details
curl "http://localhost:3000/api/v1/runs/{runId}" \
  -H "x-api-key: YOUR_API_KEY"

Error Handling

The Workflows API provides robust error handling at multiple levels.

Step-Level Retries

Configure automatic retries for transient failures using retryConfig:

{
  "id": "call-api",
  "type": "action",
  "config": { ... },
  "retryConfig": {
    "maxAttempts": 3,
    "initialDelayMs": 1000,
    "maxDelayMs": 30000,
    "backoffMultiplier": 2
  }
}
OptionTypeDescription
maxAttemptsnumberMaximum retry attempts (1-10)
initialDelayMsnumberInitial delay in milliseconds (min: 100)
maxDelayMsnumberMaximum delay between retries (min: 1000)
backoffMultipliernumberMultiplier for exponential backoff (1-10)

Error Strategies

Define how to handle step failures using errorHandling:

{
  "id": "optional-step",
  "type": "action",
  "config": { ... },
  "errorHandling": {
    "strategy": "continue",
    "fallback": {
      "defaultValue": "N/A"
    }
  }
}
StrategyBehavior
failStop workflow, mark run as failed (default)
continueLog error, continue to next step
retryRetry with configured retryConfig settings

The optional fallback object provides default output values when a step fails with continue strategy.

Timeout Configuration

Prevent steps from hanging indefinitely with timeoutMs:

{
  "id": "slow-api",
  "type": "action",
  "config": { ... },
  "timeoutMs": 60000
}

Versioning

Workflows support version control to track changes over time.

How Versioning Works

  1. Create - Initial workflow is version 1
  2. Update - Each update to an active workflow creates a new version
  3. Execution - Running workflows complete with their started version
  4. Rollback - Revert to any previous version

Version API

# List versions
curl "http://localhost:3000/api/v1/workflows/{id}/versions" \
  -H "x-api-key: YOUR_API_KEY"
 
# Get specific version
curl "http://localhost:3000/api/v1/workflows/{id}/versions/3" \
  -H "x-api-key: YOUR_API_KEY"
 
# Rollback to version
curl -X POST "http://localhost:3000/api/v1/workflows/{id}/versions/3/rollback" \
  -H "x-api-key: YOUR_API_KEY"

Version States

StateDescription
currentActive version used for new runs
archivedPrevious version, available for rollback
rollbackVersion restored from rollback operation

Best Practices

Naming Conventions

  • Use descriptive workflow names: Invoice Customer on Deal Close
  • Use verb-noun step IDs: transform-payment, send-notification
  • Include context in descriptions

Idempotency

Design workflows to be safely re-run:

{
  "id": "create-or-update",
  "type": "action",
  "config": {
    "connector": "stripe",
    "action": "createCustomer",
    "params": {
      "idempotencyKey": "{{input.deal_id}}"
    }
  }
}

Error Recovery

  • Use appropriate retry counts for each integration
  • Set reasonable timeouts
  • Use onError: continue for non-critical steps

Testing

  • Start with draft status for development
  • Use API trigger for manual testing
  • Check run history for debugging

Next Steps