Skip to main content

Building Workflows

Workflows are the core of your automation. They connect individual steps together to move data, make decisions, and interact with external systems.

In the @culvii/kit SDK, you build workflows by creating Step instances and connecting them, then wrapping them in a Workflow.

Create your first workflow

Every workflow needs steps. Let's start with a simple manual trigger that passes data to an output step.

import { Step, Workflow } from '@culvii/kit';

// 1. Create the trigger
const trigger = new Step({
name: 'Manual Trigger',
type: 'manualTrigger',
});

// 2. Create an action step
const output = new Step({
name: 'Set Output Data',
type: 'core.set',
params: {
values: {
triggered: true,
source: 'sdk',
},
},
});

// 3. Connect them
trigger.connectTo(output);

// 4. Group them into a workflow
const workflow = new Workflow({
name: 'My First Workflow',
steps: [trigger, output],
});

Step IDs and Names

By default, the SDK generates a unique ID for each step. If you want stable snapshots for testing, you can provide your own id.

The name must be unique within the workflow. Don't put dynamic runtime data in the step name. Use params for that.

const step = new Step({
id: 'enrich-lead-step',
name: 'Enrich Lead',
type: 'core.set',
});

Chaining steps and passing data

When you call source.connectTo(target), you create a connection from the main output of the first step to the main input of the second. Data flows automatically along this path.

trigger.connectTo(enrichLead);
enrichLead.connectTo(notifySales);

Conditional logic and multiple outputs

Some steps have multiple outputs, like an "If" node that routes data based on a condition. You can specify exactly which output connects to which input using connection options.

// Connect the "true" branch (output index 0) to the success step
checkCondition.connectTo(handleSuccess, {
fromPort: 'main',
fromOutputIndex: 0,
toInputIndex: 0,
});

// Connect the "false" branch (output index 1) to the fallback step
checkCondition.connectTo(handleFallback, {
fromPort: 'main',
fromOutputIndex: 1,
toInputIndex: 0,
});

Handling errors

Things break. APIs go down. You can tell the workflow how to handle step failures using the onError property.

const step = new Step({
name: 'Notify Sales',
type: 'http',
onError: 'stopWorkflow', // Stops execution if this step fails
});

Supported error behaviors:

  • 'stopWorkflow': Halts the entire workflow.
  • 'continueErrorOutput': Routes the error data to a specific error output branch.
  • 'continueRegularOutput': Ignores the error and continues down the main path.

Adding credentials

When a step needs to talk to an authenticated API, pass the credential details directly to the step.

const step = new Step({
name: 'Call CRM',
type: 'http',
credentials: {
name: 'CRM API',
id: 'credential-id',
},
});

Adding steps later

You don't have to define everything upfront. You can create an empty workflow and add steps as you build them.

const workflow = new Workflow({
name: 'Lead Workflow',
});

// Add steps dynamically
workflow.addSteps(trigger, enrichLead, notifySales);

Just remember: if you connect a step, you must add it to the workflow's steps array. If a step connects to a missing step, the workflow will throw an error when validated.