Workflow structure
A workflow is a JSON document holding a list of actions. The builder draws it, but knowing the underlying shape is what lets you read an exported workflow or work out why one refuses to save.
The workflow
{
"id": "guid",
"tenantId": "guid",
"name": "SyncSuppliers",
"active": true,
"version": 1,
"logLevelType": "Info",
"requiresAuthentication": false,
"actions": [],
"subWorkflows": [],
"scheduler": null
}
| Field | Meaning |
|---|---|
name | Required, and cannot be empty. |
active | Whether the workflow is eligible to run. |
version | Incremented as the workflow is edited. |
logLevelType | Info, Warning or Error. Set it against how critical the workflow is. |
requiresAuthentication | Whether an inbound call must be authenticated. |
actions | The chain. See below. |
subWorkflows | Named action chains this workflow can call. |
scheduler | Present only on scheduled workflows. See How automations start. |
Chaining actions
Every action carries an actionType and a name, and the name is how the rest of the workflow refers to it. Non-terminal actions carry next, naming the action that runs after them.
{ "actionType": "Start", "name": "Start", "next": "FetchSuppliers" }
{ "actionType": "Rest", "name": "FetchSuppliers", "next": "Exit", "method": "GET", "url": "..." }
{ "actionType": "Result", "name": "Exit" }
Branching works differently: Case replaces next with nextActions, a list of candidate branches, and one of them may be marked { "default": true }.
Rules a workflow must satisfy
These are checked when the workflow is saved. A workflow that breaks any of them is rejected.
- Exactly one
Startaction. - At least one
Resultaction. - Action names are unique within the workflow, and within each sub-workflow.
- Every
nextnames an action that exists. Resultmust not carrynext.- No cycle without a way out.
Scheduled workflows add their own rules, listed under Schedules.
Sub-workflows
A sub-workflow is a named chain kept beside the main one and called by ExecuteSubWorkflow or run per item by Loop. It follows the same rules as the workflow: its own Start, its own Result, unique names inside it.
{
"name": "CreateProjectIfNotExists",
"actions": [
{
"actionType": "Start",
"name": "Start",
"next": "Exit"
},
{
"actionType": "Result",
"name": "Exit",
"httpResponse": {
"statusCode": 200,
"headers": { "content-type": "application/json" },
"body": ""
}
}
]
}
Reach for one when the same few actions repeat, and whenever you need Loop, which runs a sub-workflow per element.
When an action fails
Some actions accept nextOnError alongside next. When the action fails, the chain continues at the action nextOnError names instead of stopping. Use it for failures you can recover from: fall back to a default, log and carry on, or return a considered error from Result.
Without nextOnError, a failing action ends the run.
Practices worth keeping
Keep only the fields an action needs, and drop the ones left null. An exported workflow full of unused properties is hard to read and hides the fields that matter.
Give Case a default branch. Without one, an unmatched test is a dead end.
Name actions after what they do rather than what they are. FetchSuppliers tells the next reader more than Rest1, and the name is what every expression downstream will quote.