sync (wait for completion, max 30s) · async (fire and forget).
Sub-workflow must not contain a trigger node
The workflow referenced by workflowId must not have a trigger node — the executor calls it directly. Remove the trigger node before activating a sub-workflow. Sub-workflows can be nested up to 5 levels deep.
Outputs of each completed sub-workflow node are returned as nodeId_output keys, e.g. { "n2_output": { ... }, "n3_output": { ... } }. Access them in the parent workflow as ctx.nodeOutputs.subWorkflowNodeId.n2_output.
parallel — Fork Execution
Runs multiple branches simultaneously. Execution resumes at a merge node once all branches complete.
Field
Type
Required
Default
Description
branches
string[]
required
—
Array of node IDs that are the start of each parallel branch.
waitFor
enum
optional
all
all (wait for every branch) · any (continue as soon as one branch finishes).
log — Debug Output
Field
Type
Required
Default
Description
level
enum
optional
info
debug · info · warn · error. Visible in the run trace.
message
string
required
—
Log message. Template expressions supported.
data
any
optional
—
Additional structured data to attach to the log entry.
error_handler — Catch Errors
Catches errors thrown by upstream nodes and routes to a recovery branch. Must be connected via an onError edge.
Field
Type
Required
Default
Description
catchErrors
string[]
optional
—
Error codes to catch. Empty = catch all errors.
errorVariable
string
optional
error
Variable name for the error object: { code, message, nodeId, attemptCount }.
whatsapp — Send WhatsApp Message
Dispatches a WhatsApp message through the tenant's configured provider (Twilio or Meta Cloud API, set under Settings → Feedback Channels → WhatsApp — see the WhatsApp channel docs). Used by the built-in WhatsApp workflow templates (see the Automations reference).
Field
Type
Required
Default
Description
to
string
optional
—
Recipient phone number, an expression, or the literal "owner" (also accepts "@owner", "company_owner", "company owner", "admin") to resolve the tenant's configured owner alert number. Either this or toPhoneNumber/phone is required.
toPhoneNumber
string
optional
—
Alias for to — checked if to is not set.
phone
string
optional
—
Second fallback alias for to.
message
string
required
—
Message body. Template expressions supported. Either this or body/text is required.
mediaUrl
string
optional
—
Media URL to attach — appended on its own line to the message text if not already present (no native media API call).
waConfig
object
optional
—
Override the resolved provider credentials for this node instead of reading the tenant's Settings → Feedback Channels → WhatsApp config.
target
string
optional
—
Set to "owner" together with an empty to field as an alternative way to route to the owner alert number.
sendRealInTest
boolean
optional
false
Also accepted as sendLive / live. Sends a real message even during a Canvas test run instead of simulating it.
continueOnError
boolean
optional
false
If true, a delivery failure returns { sent: false, ... } instead of throwing and failing the run.
Phone number formatting
The resolved to value is auto-formatted before dispatch: a bare 10-digit Indian mobile number (starts with 6–9) is prefixed +91; any other 11–15 digit number with no leading + gets one prepended. Numbers already in E.164 form (+...) pass through unchanged.
Dry-run / simulated sends
During a Canvas test run the node does not call Twilio/Meta by default — it returns a simulated result ({ sent: true, simulated: true, deliveryStatus: "sent_via_twilio", note: "..." }) so test runs never burn live WhatsApp credits. The same simulation also fires outside test runs whenever to contains example.com, <, or mock. Set sendRealInTest (or sendLive / live) to true on the node config to force a real send during a test run.
If no WhatsApp provider is configured for the tenant, the node always resolves to { sent: false, deliveryStatus: "not_configured" } instead of throwing — regardless of continueOnError. Any other delivery failure (Twilio/Meta API error) throws and fails the run unless continueOnError is true. Check deliveryStatus in downstream nodes if you branch on delivery outcome.