Workflows
What a Zernio workflow is, how the trigger and node graph fit together, and how to create and activate one over the API.
A workflow is a server-side automation attached to one connected messaging account: a single trigger node followed by a directed graph of action nodes. When the trigger fires, Zernio walks the graph for that conversation, sending messages, waiting for replies, branching, calling your webhooks, and handing off to a human when needed.
Workflows are not WhatsApp Flows (Meta's in-chat forms). A workflow can send a flow, but they are separate products. Workflows require inbox access: without it every /v1/workflows/* call returns 403 with code INBOX_REQUIRED.
Triggers
Every workflow has exactly one trigger node. Its config.triggerType decides what starts a run:
triggerType | Starts when |
|---|---|
inbound_message (default) | The connected account receives a DM. Optional keywords plus matchType (any, contains, exact, regex) filter which messages match; onlyFirstMessage: true fires once per contact. |
api_call | Your backend starts a run explicitly with Manually start a workflow run. |
whatsapp_event | A WhatsApp status event arrives (eventType: message_sent, message_delivered, message_read, message_failed, reaction). WhatsApp only. |
Supported platforms: whatsapp, instagram, facebook, telegram, twitter, bluesky, reddit.
Nodes and edges
The graph is nodes[] plus edges[]. Each node has a stable id, a type, and a type-specific config; each edge links a source node to a target node. A node with more than one outcome takes the edge whose sourceHandle matches: a condition takes the matched rule's id or default, wait_for_reply takes reply or timeout, webhook takes success or error. An edge without sourceHandle is the node's single or default output.
The 16 node types:
- Messaging:
send_message(text, media, and on WhatsApp also template and interactive messages). - Control flow:
trigger,condition,delay,wait_for_reply,a_b_split,end. - Data:
set_variable(run-scoped),set_field(persisted on the contact),add_tag,remove_tag,enroll_sequence. - Integrations:
webhook,ai(your own LLM provider key),handoff,start_call(WhatsApp only).
Every string in config accepts {{variable}} interpolation against the run's variables: lastMessage, anything captured with saveAs, and set_variable assignments. The full config shape per node type is documented on Create workflow.
Create and activate a workflow
A workflow is created in draft status. Activation validates that the graph is runnable (one trigger node and a reachable entry) and only then do inbound messages start runs. This example greets a WhatsApp contact, waits for their name, and replies with it.
curl -X POST "https://zernio.com/api/v1/workflows" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "66a1f0c2a4b9d3e8f1a2b3c4",
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"platform": "whatsapp",
"name": "Welcome",
"nodes": [
{ "id": "n_trigger", "type": "trigger", "config": { "triggerType": "inbound_message", "keywords": ["hi", "hello"], "matchType": "contains", "onlyFirstMessage": true } },
{ "id": "n_ask", "type": "send_message", "config": { "messageType": "text", "text": "Hi! What is your name?" } },
{ "id": "n_wait", "type": "wait_for_reply", "config": { "saveAs": "name", "timeoutMinutes": 10 } },
{ "id": "n_reply", "type": "send_message", "config": { "messageType": "text", "text": "Thanks {{name}}, a teammate will be with you shortly." } },
{ "id": "n_end", "type": "end" }
],
"edges": [
{ "id": "e1", "source": "n_trigger", "target": "n_ask" },
{ "id": "e2", "source": "n_ask", "target": "n_wait" },
{ "id": "e3", "source": "n_wait", "target": "n_reply" },
{ "id": "e4", "source": "n_reply", "target": "n_end" }
]
}'const { data } = await zernio.workflows.createWorkflow({
body: {
profileId: '66a1f0c2a4b9d3e8f1a2b3c4',
accountId: '66b2e19d8c3f5a7e9d0b1c2d',
platform: 'whatsapp',
name: 'Welcome',
nodes: [
{ id: 'n_trigger', type: 'trigger', config: { triggerType: 'inbound_message', keywords: ['hi', 'hello'], matchType: 'contains', onlyFirstMessage: true } },
{ id: 'n_ask', type: 'send_message', config: { messageType: 'text', text: 'Hi! What is your name?' } },
{ id: 'n_wait', type: 'wait_for_reply', config: { saveAs: 'name', timeoutMinutes: 10 } },
{ id: 'n_reply', type: 'send_message', config: { messageType: 'text', text: 'Thanks {{name}}, a teammate will be with you shortly.' } },
{ id: 'n_end', type: 'end' },
],
edges: [
{ id: 'e1', source: 'n_trigger', target: 'n_ask' },
{ id: 'e2', source: 'n_ask', target: 'n_wait' },
{ id: 'e3', source: 'n_wait', target: 'n_reply' },
{ id: 'e4', source: 'n_reply', target: 'n_end' },
],
},
});
await zernio.workflows.activateWorkflow({ path: { workflowId: data.workflow.id } });The create call returns the draft:
{
"success": true,
"workflow": {
"id": "66d4a1b2c3e4f5a6b7c8d9e1",
"name": "Welcome",
"platform": "whatsapp",
"status": "draft",
"nodeCount": 5,
"entryNodeId": "n_trigger",
"createdAt": "2026-09-07T12:00:00.000Z"
}
}Then activate it. A 400 here names the structural problem (no trigger node, unreachable nodes, a WhatsApp-only node on another platform):
curl -X POST "https://zernio.com/api/v1/workflows/66d4a1b2c3e4f5a6b7c8d9e1/activate" \
-H "Authorization: Bearer YOUR_API_KEY"
# { "success": true, "workflow": { "id": "66d4a1b2c3e4f5a6b7c8d9e1", "status": "active", "entryNodeId": "n_trigger" } }Status and runs
A workflow moves draft to active to paused. Pause stops matching new messages while in-flight runs finish; activate again to resume. Every edit to the graph through Update workflow records a version you can restore. If a workflow "does nothing", check its status first: a draft or paused workflow never fires.
List workflow runs returns each execution with its status (running, waiting, completed, exited, failed), current node, and accumulated variables; the run timeline shows every node visited. To test a graph without a real inbound message, use Manually start a workflow run with to (WhatsApp) or conversationId (other platforms) plus an optional text to seed lastMessage.
Reference
List workflows, Get workflow, Update workflow, Delete workflow, Duplicate workflow, Get workflow version.