Getting started with workflows
Create your first automated workflow in the dcupl Console. This tutorial walks you through building a data processing pipeline using the visual editor.
What you'll build
flowchart LR
T[Webhook Trigger] --> F[Fetch Products]
F --> V{Validate}
V -->|Valid| Tr[Transform]
V -->|Invalid| L[Log Error]
Tr --> R[Return Response]
A workflow that:
- Receives a webhook request with the number of products to fetch
- Fetches those products from a public sample API (dummyjson.com)
- Validates them: a product needs a title, a price and at least 50 items in stock
- Transforms the valid products
- Logs the invalid ones
- Returns the transformed products as JSON
Prerequisites
- A dcupl Console account at console.dcupl.com
- A project created in the Console, where you are an owner or editor (the Workflows menu isn't shown to viewers)
- A runner instance available for deployment
Step 1: create a new workflow
- Open your project in the Console (the draft version)
- Click Workflows in the left sidebar
- On the Templates tab, click + (Create a new workflow template)
- Fill in the details:
- Workflow Name: Product Sync
- Workflow Key: product-sync
- Description: Fetches and processes product data
- Template: From Scratch (HTTP)
- Click Create Workflow
The workflow editor opens with the template: an HTTP Trigger connected to a Status Response. Click Edit Workflow to start editing.
Step 2: add a webhook trigger
- Open the HTTP Trigger node the template created (to add one yourself, drag HTTP Request from the Trigger section of the node palette)
- Configure the webhook:
- Path:
/products/sync - Methods: Select
POST
- Path:
Changes apply as you edit; you save the whole workflow in Step 8. This creates an endpoint that will trigger your workflow when it receives HTTP requests.
Step 3: add an HTTP Request node
From the Nodes section of the palette, drag an HTTP Request node onto the canvas
Connect the trigger's output port to the request node's input port
Name it "Fetch Products", set Method to
GET, and set URL to:{{variables.productsApiUrl}}?limit={{request.body.limit}}&select=title,price,stock
{{variables.productsApiUrl}} reads a workflow variable, which you add in Step 7. {{request.body.limit}} reads the limit field of the webhook's JSON body; a run whose body has no limit fails at this node with Unresolved template placeholder {{request.body.limit}}.
Step 4: add validation logic
- Drag a Script node onto the canvas
- Connect the request node's
mainoutput to the script node - Name it "Validate Products"
- On the node's Ports & Schema tab, click + Add Output twice to add the output ports
validandinvalid - In the script editor, check each product and send it to the matching port:
// The HTTP Request node emits one item: { body, headers, statusCode, ... }.
// The sample API answers { products: [...], total, skip, limit }.
const products = $json.first().body.products || [];
const isValid = (p) => Boolean(p.title) && p.price > 0 && p.stock >= 50;
return _output.route({
valid: products.filter(isValid),
invalid: products.filter((p) => !isValid(p)),
});$json.first() is the first incoming item's data; $json() returns all of them. Returning a plain value or array sends it to the main port instead.
Step 5: add conditional routing
Route valid products
- Drag another Script node onto the canvas and name it "Transform Products"
- Connect the validation node's
validport to it - Give it this script, which turns each valid product into the shape the response returns:
// One item per valid product arrives here
return $json().map((p) => ({ id: p.id, name: p.title, price: p.price, stock: p.stock }));Route invalid products
- Drag a Script node onto the canvas and name it "Log Errors"
- Connect the validation node's
invalidport to it - Give it this script:
// One item per invalid product arrives here (none when every product is valid)
$json().forEach((p) => console.log('low stock', p.id, p.title, p.stock));
// End this branch without items, so it does not change what the run answers
return [];console.log output is recorded when you test with Enable Data Trace (Step 9). A script that returns nothing passes its input on, and a branch that ends with items can become part of the run's answer, so the script returns an empty array.
Your workflow now has two parallel paths from the validation node. Connect every custom port that can receive items: items on an unconnected port go to the node's error port, and the run fails if that isn't connected either.
Don't route with edge conditions: the editor lets you add a condition to an edge, but the workflow runner currently ignores it and passes every item through.
Step 6: configure the response
The template's Status Response node returns only the execution status (status, executionId, duration). To return the transformed products instead:
- Delete the Status Response node
- From the Response section of the palette, drag a Script Response node onto the canvas
- Connect the "Transform Products" node's
mainoutput to it - Give it this script:
// `data` holds the incoming items' JSON: the transformed products
return { count: data.length, products: data };Return an object: what the script returns is the response body, and an array would arrive as an object with the keys "0", "1", ….
Step 7: add variables
Keep the API's base URL in a workflow variable, so you can point the workflow at another API without editing nodes.
- Click the key icon (Project Variables) in the workflow toolbar
- In Global Workflow Variables, add the variable:
- Name:
productsApiUrl - Value:
https://dummyjson.com/products
- Name:
- Click Add Variable
Variable values are masked in the list and encrypted with the runner's key when you deploy, so variables are also where API tokens belong (Bearer {{variables.apiToken}} in a header). Until productsApiUrl exists, Deploy stays disabled and offers Define Variables.
Step 8: save and deploy
Save your workflow
Click Save Changes in the toolbar.
Deploy to runner
- Select your target runner in the runner dropdown of the toolbar
- Click Deploy
- Wait for the runner's status to change to Up to date
Step 9: test your workflow
From the Console
- Click Execute in the toolbar — the Test Workflow panel opens on its New Test tab
- Enter
{ "limit": 5 }as the Request Body (JSON), and turn on Enable Data Trace to record the "Log Errors" output - Click Start Test
- View the execution results below the form
- Open a node on the canvas to see its input and output data, or check the History tab for past runs
Using cURL
curl -X POST \
'https://<runner-url>/v3/workflow/<project-id>-product-sync/products/sync' \
-H 'Content-Type: application/json' \
-d '{ "limit": 5 }'The runner URL is shown on the Workflows page, and the deployed workflow key is your key prefixed with the project ID. The test panel's Request Preview shows the exact command. If you added API-key authentication to the trigger, also send the key in an api-key header.
Expected result
The run answers with what the Script Response returns. With the sample API's current data, four of the first five products have at least 50 items in stock; the fifth goes to "Log Errors":
{
"count": 4,
"products": [
{ "id": 1, "name": "Essence Mascara Lash Princess", "price": 9.99, "stock": 99 },
{ "id": 3, "name": "Powder Canister", "price": 14.99, "stock": 89 },
{ "id": 4, "name": "Red Lipstick", "price": 12.99, "stock": 91 },
{ "id": 5, "name": "Red Nail Polish", "price": 8.99, "stock": 79 }
]
}The sample data belongs to dummyjson.com and may change. The whole workflow as a template file is the example on the template reference.
Troubleshooting
Workflow not triggering
- Verify the endpoint URL is correct
- If the trigger has API-key authentication, check the key is sent in the
api-keyheader - Ensure the runner status shows Up to date
Script errors
- Open the failing node on the canvas to see its error and input data
- Verify
$json()returns data - Use
console.log()in scripts and run the test with Enable Data Trace to capture the logs - Scripts time out after 500 ms by default
HTTP request failures
- Check the target URL is accessible
- Verify authentication headers are correct
- Review the error output port for details
Connection issues
- Ensure all required input ports are connected
- Check that every output port that receives items is connected
- Verify the workflow is saved and deployed (status Up to date)