A Workflow is an automation graph that runs at the account level — not tied to any single agent. Workflows fire on triggers (conversation events, schedules, incoming webhooks), execute a graph of nodes, and can call external APIs, transform data, write to Tables, send messages, etc.
If a Flow is "what the agent says next", a Workflow is "what happens around the agent".
| Field | Type | Notes |
|---|---|---|
id | number | Use as workflowId. |
name | string | |
description | string? | |
status | enum | ACTIVE · DRAFT · PAUSED · ARCHIVED. |
triggerType | enum? | E.g. CONVERSATION_ENDED, CONVERSATION_STARTED, SCHEDULED, etc. |
runsCount | number | Total executions. |
runsFailedCount | number | Total failed executions. |
lastRunDate | string? | ISO timestamp of the most recent run. |
liveSnapshotId | string? | Published snapshot. |
draftSnapshotId | string? | Working draft. |
| Type | Purpose |
|---|---|
TRIGGER | Event-based entry point (conversation ended, contact created, …). |
SCHEDULED_TRIGGER | Cron-style entry point. |
WEBHOOK | Entry point fed by an Incoming Webhook. |
API | Call an external HTTP endpoint. |
TOOLS_AI | Let the AI choose a Tool to call. |
CONDITIONAL_ROUTING | Branch based on AI-evaluated conditions. |
AI_CAPTURE | Extract structured data from text using an LLM. |
DATA_TRANSFORMER | Reshape data via prompt. |
DYNAMIC_TABLES | Create, update, delete, search, or change the record type of records in a Table or Object. |
CREATE_RECORD_ACTIVITY | Log a manual activity (note, call, meeting, email, WhatsApp) on a specific Object record. |
ITERATION | Loop over an array variable (body / completed / empty handles). |
BREAK | Exit the current loop early and continue on the loop's completed path. |
AUTOMATION_STATUS | Set another automation live, draft, or toggle its status. |
SEND_MESSAGE | Push a message to a conversation. |
SEND_WHATSAPP_MESSAGE | Send a WhatsApp Business template to a phone number or People record. |
TRANSCRIPTION | Transcribe an audio URL. |
FILE_ANALYSIS | OCR + AI analysis of a file from a URL. |
Each node carries nodeId, alias, position, type, and a typed data payload.
Reference validation: on create/update, the API validates every cross-resource reference inside
data—aiModelId,customToolIds,tableId,recordTypeId,triggeredByAgentIds[],triggerByWebhookIds[],connectedAccountId,knowledgeBaseIds, etc. If any referenced id does not exist or does not belong to your account, the request returns400 bad_requestwithdetails.issues[].code === "not_found"and the node is not persisted. See Errors.Schema-level checks also apply to
SCHEDULED_TRIGGER(cronExpressionvalidated bycron-validate,timezoneagainst IANA),WEBHOOKandAPI(urlmust be a valid URL).
Automation workflows expose one runtime variable per node, with name = nodeId. A node api_1 can be referenced downstream as {api_1}. This is in addition to explicitly declared Workflow Variables.
Interpolable fields include the same set as Flows, plus:
- AI Capture:
prompt,instructions. - Data Transformer:
prompt. - Tools AI:
instructions,prompt. - Transcription:
audioUrl. - Create Record Activity:
rowId,content. - WhatsApp template variables:
templateVariables.header,body,buttons.
Capturing specific values. The API node can extract values from its JSON response into named variables via its variables field ({ key, value, fullResponse }), and AI_CAPTURE / TOOLS_AI / TRANSCRIPTION populate variables via captureVariables. All capture targets must reference a variable that already exists (create it first via POST /workflows/{workflowId}/variables). In captureVariables you may reference it by { "name": "<var>" } or { "id": <id> } — the API resolves and links it to the canonical { id, name, description }; an unknown name/key returns 400. For the API node's value path syntax (dot/[n] property access into the JSON response), see Flows → API node response paths.
Logs a manual activity on a specific Object record at workflow runtime.
{
"nodeId": "node_create_activity_1",
"type": "CREATE_RECORD_ACTIVITY",
"position": { "positionX": 640, "positionY": 0 },
"data": {
"type": "CREATE_RECORD_ACTIVITY",
"recordTypeId": 5,
"rowId": "{contact_row_id}",
"activityType": "PHONE_CALL",
"content": "Llamada de seguimiento: {call_summary}"
}
}| Field | Required | Notes |
|---|---|---|
recordTypeId | ✅ | Numeric id of the Object's record type. Validated: must exist and belong to your account. |
rowId | ✅ | MongoDB ObjectId of the record to log on. Supports {varName} interpolation. |
activityType | ✅ | One of: NOTE, EMAIL, PHONE_CALL, MEETING, WHATSAPP. Validated at save time. |
content | ✅ | Activity body text. Supports {varName} interpolation. |
Validation: recordTypeId must point to a real record type on an Object (not a Table) in your account. activityType must be a valid enum value. Variables in rowId and content must exist — the API returns 400 with the offending variable name if any reference is unknown.
Iterates over an array stored in a workflow variable. The wire type is ITERATION.
{
"nodeId": "node_loop_1",
"type": "ITERATION",
"alias": "Loop",
"position": { "positionX": 320, "positionY": 0 },
"data": {
"type": "ITERATION",
"variableName": "items",
"variablePath": "data.items",
"continueOnError": false
}
}| Field | Notes |
|---|---|
variableName | Name or alias of an existing workflow variable. Must resolve to an array at runtime. |
variablePath | Optional dot path inside the variable (e.g. data.items when the variable holds a full API response). |
continueOnError | When true, a failed item inside the loop is skipped. When false, any failure stops the automation. |
Edges: connect three outgoing handles — body (for-each), completed (after all items), empty (null/empty list; does not route to completed). Inside the loop, {<loopNodeId>.item}, {<loopNodeId>.index}, and {<loopNodeId>.length} are available (use the loop node's nodeId from the graph). {<loopNodeId>.item} is the entire current item (JSON if object) — there is no {<loopNodeId>.item.field} dot-access. DYNAMIC_TABLES SEARCH stores a top-level array of rows; leave variablePath empty when looping that output.
Exits the current loop and continues on the loop's completed path. Place only inside a Loop body branch; outside an active loop the automation fails.
{
"nodeId": "node_break_1",
"type": "BREAK",
"position": { "positionX": 640, "positionY": 0 },
"data": { "type": "BREAK" }
}Changes another automation's status (SET_ACTIVE, SET_DRAFT, or TOGGLE). Does not publish draft graph changes.
{
"nodeId": "node_status_1",
"type": "AUTOMATION_STATUS",
"position": { "positionX": 320, "positionY": 0 },
"data": {
"type": "AUTOMATION_STATUS",
"automationId": 1,
"action": "SET_ACTIVE"
}
}automationId is validated at save time — it must exist in your account.
Sends a WhatsApp Business template message. Distinct from SEND_MESSAGE (conversation push).
{
"nodeId": "node_wa_1",
"type": "SEND_WHATSAPP_MESSAGE",
"position": { "positionX": 320, "positionY": 0 },
"data": {
"type": "SEND_WHATSAPP_MESSAGE",
"recipientMode": "PHONE_NUMBER",
"personName": "{first_name} {last_name}",
"phoneNumber": "{phone_number}",
"phoneNumberId": "1132681309928224",
"template": "hello_world",
"templateVariables": { "body": { "1": "{first_name}" } }
}
}| Field | Notes |
|---|---|
recipientMode | PHONE_NUMBER (default) or PEOPLE_RECORD. |
personName | Required in PHONE_NUMBER mode. Supports {var} interpolation. |
phoneNumber | Required in PHONE_NUMBER mode. Full international format. Supports {var}. |
peopleRowId | Required in PEOPLE_RECORD mode. People record ObjectId. Use {var} or {<loopNodeId>.item} when looping scalars — not {<loopNodeId>.item.id}. |
phoneNumberId | Meta WhatsApp Business phone number id. Must exist and have an assistantId (validated). |
template | Approved template name. |
templateVariables | Maps template parameter ids to values (body, header, buttons). |
Resolve phoneNumberId and template via the read-only integrations endpoints below.
| Verb | Path | Purpose |
|---|---|---|
GET | /public/v1/integrations | List connected WhatsApp numbers, Instagram accounts, Messenger pages |
GET | /public/v1/integrations/whatsapp/templates | List APPROVED WhatsApp templates from Meta for this account |
For SEND_WHATSAPP_MESSAGE, use a WhatsApp number where canSendMessages is true (an assistant is assigned).
| Verb | Path | Purpose |
|---|---|---|
GET | /public/v1/workflows | List, with status filter |
POST | /public/v1/workflows | Create |
GET | /public/v1/workflows/{workflowId} | Detail (?includeNodes=true for nodes) |
PUT | /public/v1/workflows/{workflowId} | Update metadata / status |
DELETE | /public/v1/workflows/{workflowId} | Soft delete + cleanup of triggers |
GET | /public/v1/workflows/{workflowId}/graph | Full graph |
POST | /public/v1/workflows/{workflowId}/nodes | Create node |
PUT | /public/v1/workflows/{workflowId}/nodes/{nodeId} | Update node |
DELETE | /public/v1/workflows/{workflowId}/nodes/{nodeId} | Delete node + incident edges |
POST | /public/v1/workflows/{workflowId}/edges | Add edge |
DELETE | /public/v1/workflows/{workflowId}/edges | Remove edge |
GET | /public/v1/workflows/{workflowId}/analytics | Run analytics |
GET | /public/v1/workflows/{workflowId}/logs | List run logs (history) |
GET | /public/v1/workflows/{workflowId}/logs/{logId} | One run + per-node results |
Every time a workflow runs it records an execution. Read them to audit results, debug failures, or track credit usage.
List /public/v1/workflows/{workflowId}/logs — paginated, with optional status, start_date, and end_date filters. Each run (basic fields):
| Field | Notes |
|---|---|
id | Use as logId. |
successful | Whether the run completed without error. |
started_at | ISO timestamp. |
completed_at | ISO timestamp (null while running). |
duration | Milliseconds. |
operations | Number of node operations executed. |
ai_credits | AI credits consumed. |
error | Error message if the run failed. |
insufficient_credits | Run stopped because the account ran out of credits. |
prevented_loop | Run stopped because a loop was detected. |
Detail /public/v1/workflows/{workflowId}/logs/{logId} — the run above plus node_results: [{ node_id, alias, type, success, error, ai_credits, created_at }], one entry per node that executed.
frontline workflows list --table
frontline workflows create --name "Daily CRM Sync"
frontline workflows nodes create --data '{"nodeId":"trigger_1","type":"TRIGGER","position":{"positionX":0,"positionY":0},"data":{"type":"TRIGGER","triggerType":"CONTACT_CREATED"}}'
frontline workflows analytics --start-date 2026-01-01 --end-date 2026-12-31
frontline workflows logs --workflow-id 2 --table
frontline workflows logs --workflow-id 2 --status FAILED --start-date 2026-01-01
frontline workflows logs get 9001 --workflow-id 2 --pretty
frontline integrations list --table
frontline integrations whatsapp-templates --table