Skip to main content

Creating Workflows

This guide walks you through creating your first workflow, from setting up a trigger to executing and monitoring the workflow.

Prerequisites

Before creating a workflow, you’ll need:
  1. A KnoxCall account
  2. Basic understanding of APIs (HTTP requests, JSON)
Workflow executions consume a metered monthly operations quota (each run counts against your tenant’s limit based on the number of nodes). When the limit is reached, an execution is recorded as failed without running. Workflow access also depends on your plan’s feature entitlements.

Step 1: Create a New Workflow

  1. Navigate to Workflows in the sidebar
  2. Click + Create Workflow
  3. Enter workflow details:
Name: My First Workflow
Description: A simple workflow that fetches data and processes it
Environment: production (optional)
  1. Click Create
You’ll see the workflow editor with an empty canvas and a trigger node.

Step 2: Configure the Trigger

The trigger node is already on the canvas. Click it to configure:
Trigger Type: Manual
This lets you run the workflow on-demand from the UI.

Webhook Trigger

Trigger Type: Webhook
Method: POST
This creates an endpoint that triggers the workflow when called.

Route Event Trigger

Trigger Type: Route Event   # underlying triggerType: proxy_event
Event Types:                 # proxyEventConfig.eventTypes (an array)
  - request.completed
Route Filter: (optional, select specific routes)
This triggers when requests pass through your routes. The underlying trigger type is proxy_event, and event selection is an eventTypes array. Valid event types are request.received, request.success, request.error, request.client_error, request.server_error, request.timeout, and request.completed. You can also narrow matches with an optional route filter, environment filter, and field conditions.

Step 3: Add an HTTP Request Node

Let’s add a node that makes an API call:
  1. Click the + button on the trigger node’s output
  2. Select HTTP Request
  3. Configure the node:
Name: Fetch User Data

Method: GET
URL: https://jsonplaceholder.typicode.com/users/1

Headers:
  Content-Type: application/json
This calls a free test API that returns user data.

Step 4: Add a Code Block Node

Coming soon: Code Block execution is currently disabled for security and is planned for a future release. The steps below show the intended authoring experience — a Code Block does not run custom JavaScript yet (an empty Code Block simply passes its input through unchanged).
Let’s transform the response:
  1. Click the + on the HTTP Request node
  2. Select Code Block
  3. Configure:
Name: Transform Data
  1. Enter the code:
// `input` is the raw output of the single upstream node (the HTTP Request).
// For an HTTP Request node the response body is under `input.body`.
const user = input.body;

// Transform and return new data
return {
  id: user.id,
  fullName: user.name,
  email: user.email,
  company: user.company.name,
  processed_at: new Date().toISOString()
};
A Code Block receives the upstream node’s output directly as the global input (when a single edge feeds it). There is no input.nodes['<Node Name>'] lookup. For fan-in (multiple incoming edges), input is an array of { nodeId, output } entries keyed by node id, not name.

Step 5: Add a Condition Node

Let’s add conditional logic:
  1. Click the + on the Code Block node
  2. Select Condition
  3. Configure:
Name: Check User ID
Logic: AND
Conditions:
  - Type: equals
    Path: $.id
    Value: 1
Condition nodes evaluate a structured list of conditions (each with a type, a JSONPath path, and a comparison value) combined with the logic operator (AND or OR). They do not take a free-form JavaScript expression string. Reference upstream data with the JSONPath path rather than an inline {{...}} placeholder. This creates two paths:
  • True: When user ID equals 1
  • False: When user ID doesn’t equal 1

Step 6: Add Nodes to Each Branch

True Path

  1. Click the + on the Condition’s True output
  2. Select Code Block
  3. Name it: “Success Response”
  4. Code:
// The Condition node passes its data through as `input.input`, and reports the
// branch result as `input.conditionMet`.
return {
  status: 'success',
  message: 'User verified!',
  data: input.input
};

False Path

  1. Click the + on the Condition’s False output
  2. Select Code Block
  3. Name it: “Error Response”
  4. Code:
// `input.input` is the data the Condition node evaluated and passed through.
return {
  status: 'error',
  message: 'User verification failed',
  expected_id: 1,
  received_id: input.input.id
};

Step 7: Save Your Workflow

  1. Click Save in the top right
  2. Your workflow is saved as version 1
Your workflow should look like this:
[Trigger]

[Fetch User Data] (HTTP Request)

[Transform Data] (Code Block)

[Check User ID] (Condition)
    ↓           ↓
   True        False
    ↓           ↓
[Success]   [Error]

Step 8: Test Your Workflow

Manual Execution

  1. Click Run in the top right
  2. (Optional) Add input data for the trigger:
{
  "test": true
}
  1. Click Execute

Watch Execution

You’ll see:
  • Each node highlights as it executes
  • Green checkmark when successful
  • Red X if an error occurs
  • Execution time per node

View Results

Click on any node to see:
  • Input: Data that went into the node
  • Output: Data that came out
  • Execution Time: How long it took

Step 9: Enable the Workflow

  1. Toggle Enabled to ON
  2. Your workflow is now active
For webhook triggers, you’ll now see the webhook URL to call.

Adding More Nodes

HTTP Request with POST

Name: Create Record
Method: POST
URL: https://api.example.com/records

Headers:
  Content-Type: application/json

Body:
  name: "{{transform_data.output.fullName}}"
  email: "{{transform_data.output.email}}"
  source: "workflow"
Variable references use upstream node ids, e.g. {{transform_data.output.fullName}}. There is no {{env.*}} placeholder, and stored-secret injection into a node’s auth is not yet available — see Secrets.

Loop Over Array

Name: Process Items
Loop Type: array
Max Iterations: 100
Array Config:
  Array Path: $.items     # JSONPath to the array in the node input
  Item Variable: item     # name used for the current item
  Batch Size: 1           # optional, items processed per batch
The loop reads the array at arrayConfig.arrayPath from the node input and exposes the current element under the variable named in arrayConfig.itemVariable (here, item). There is no {{loop.*}} placeholder; downstream references use the item variable name you configured.

Delay

Name: Wait Before Retry
Duration: 5
Unit: seconds

Error Handler

  1. Add an Error Handler node
  2. Connect it to nodes that might fail
  3. Configure what to catch:
Name: Handle API Errors
Catch From: Fetch User Data, Create Record
  1. Add nodes after the error handler for recovery:
// In a Code Block after Error Handler. The Error Handler's output is the
// `input` here; the caught error message is exposed as `input.originalError`.
return {
  error_logged: true,
  original_error: input.originalError,
  timestamp: new Date().toISOString()
};

Using Variables

Variable references use a single form: {{<nodeId>.<path>}}, where <nodeId> is the id of an upstream node and <path> is a dot-notation path (with optional [index] array access) into that node’s output. There are no nodes['Name'], env., or loop. namespaces.

Previous Node Output

// Access output from an upstream node by its node id
{{fetch_user_data.body.id}}
{{fetch_user_data.body.email}}
For an HTTP Request node, available fields include status, statusText, headers, body, url, method, and success.

Trigger Data

// The trigger node's output is available under its node id
{{trigger.data.user_id}}
The trigger alias resolves only when the trigger node’s id is exactly trigger-node. The trigger output exposes type, data, and timestamp — the data you provide when running the workflow is under data.

Secrets

Secret injection in workflows is coming soon. There is no {{env.X}} placeholder, and stored-secret injection is not yet wired up: the engine’s secret loader is not implemented, so a node’s secret_ref auth does not yet inject a value at runtime. Until it ships, pass any required credentials through the trigger payload or an upstream node’s output.

Workflow Examples

Simple API Call

Trigger (Manual)

HTTP Request (GET https://api.example.com/data)

Code Block (Format response)

Data Sync

Trigger (Webhook)

HTTP Request (Fetch from Source API)

Loop (For each record)

HTTP Request (Push to Destination API)

Error Handling

Trigger

HTTP Request → Error Handler → Slack Notification

Code Block

Condition
    ↓         ↓
Success    Failure
    ↓         ↓
Continue   Log Error

Execution History

View past executions:
  1. Open the workflow
  2. Click Executions tab
  3. See list with:
    • Status (completed, failed, running, cancelled)
    • Started at
    • Duration
    • Trigger type
Click any execution to see:
  • Full node-by-node timeline
  • Input/output for each node
  • Error details

Versioning

Each time you save, a new version is created:
  1. Click Versions tab
  2. See all saved versions
  3. Click a version to view it
Version history is viewable today (you can list every saved version and inspect it). One-click Restore/rollback to a previous version is coming soon — there is currently no restore action. To roll back manually, open the version you want and re-save its definition as a new version.

Troubleshooting

”Variable not found”

Error: Cannot read property 'data' of undefined
Cause: Referencing a node that hasn’t executed yet or doesn’t exist. Fix: Check node names match exactly (case-sensitive).

”HTTP Request failed”

Error: ECONNREFUSED
Cause: Target API is unreachable. Fix:
  • Verify URL is correct
  • Check if API requires authentication
  • Ensure API is accessible from the internet

”Code Block error”

Error: Unexpected token
Cause: JavaScript syntax error. Fix: Check your code for:
  • Missing brackets
  • Incorrect variable references
  • Invalid JSON

”Condition always false”

Cause: Comparison type mismatch, or a wrong JSONPath in the condition. Fix: Check the condition’s path resolves to the value you expect, and pick the matching condition type:
# String comparison
- Type: equals
  Path: $.status
  Value: success

# Number comparison
- Type: greater_than
  Path: $.count
  Value: 0

Best Practices

  1. Name nodes descriptively - “Fetch Customer Data” not “HTTP 1”
  2. Add error handlers for external API calls
  3. Test with sample data before enabling
  4. Use a secret reference (secret_ref auth) for credentials instead of hard-coding them
  5. Keep workflows focused - one purpose per workflow
  6. Document complex logic in node names/descriptions

Next Steps

Workflows Overview

Understanding workflow concepts

Webhooks

Trigger workflows from webhooks

API Logs

Debug workflow API calls

Route Examples

API patterns to use in workflows

Statistics

  • Level: beginner
  • Time: 12 minutes

Tags

workflows, tutorial, getting-started, automation