Workflows
Automate actions in response to events using ChatDrift's visual workflow builder.
Workflows
A workflow is a sequence of nodes that runs automatically when a trigger event fires. You can build workflows in the visual editor — no code required — or configure them programmatically using the JSON schema described here.
Core concepts
| Concept | Description |
|---|---|
| Trigger | The event that starts the workflow. Every workflow has exactly one trigger node. |
| Node | A single step. Nodes belong to one of five categories: Trigger, Action, Data, AI, or Control. |
| Graph | The full workflow: an ordered list of nodes with edges connecting them. |
| Run | One execution of the workflow graph for a specific trigger event. |
Trigger nodes
A trigger node sits at the start of every workflow. It determines which event starts the run and can optionally filter which events qualify.
Form Submitted
Fires when a visitor submits a ChatDrift form widget.
| Config field | Type | Required | Description |
|---|---|---|---|
formId | string | No | Only fire for a specific form. Leave blank to match all forms. |
Example config
{
"type": "trigger.form-submitted",
"config": { "formId": "form_abc123" }
}
Ticket Created
Fires when a support ticket is created.
| Config field | Type | Required | Description |
|---|---|---|---|
priority | "low" | "medium" | "high" | "urgent" | No | Only fire for tickets with this priority. |
status | string | No | Only fire for tickets with this status. |
Example config
{
"type": "trigger.ticket-created",
"config": { "priority": "urgent" }
}
Contact Created
Fires when a new contact is created.
| Config field | Type | Required | Description |
|---|---|---|---|
source | string | No | Only fire for contacts from this source (e.g. "widget", "api"). |
Example config
{
"type": "trigger.contact-created",
"config": { "source": "widget" }
}
Contact Updated
Fires when an existing contact is updated.
| Config field | Type | Required | Description |
|---|---|---|---|
source | string | No | Only fire for updates from this source. |
Webhook Received
Fires when an HTTP POST is sent to your workflow's unique webhook URL.
| Config field | Type | Required | Description |
|---|---|---|---|
secret | string | No | Optional HMAC secret for verifying incoming requests. |
Schedule
Fires on a recurring cron schedule.
| Config field | Type | Required | Description |
|---|---|---|---|
cron | string | Yes | A standard 5-part cron expression (e.g. 0 8 * * 1-5 = weekdays at 8am UTC). |
Example config
{
"type": "trigger.schedule",
"config": { "cron": "0 8 * * 1-5" }
}
Human Handoff Requested
Fires when a conversation is escalated to a human agent from an AI agent.
| Config field | Type | Required | Description |
|---|---|---|---|
agentId | string | No | Only fire for handoffs from a specific AI agent. |
Action nodes
Action nodes perform real-world operations: sending messages, creating records, calling external APIs.
Send Message
Sends a message to a contact via a push channel.
| Config field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Recipient — use {{trigger.contactId}} or a literal contact ID. |
message | string | Yes | Message text. Supports {{variable}} templating. |
Example config
{
"type": "action.send-message",
"config": {
"to": "{{trigger.contactId}}",
"message": "Hi {{contact.firstName}}, thanks for getting in touch!"
}
}
Create Ticket
Creates a support ticket.
| Config field | Type | Required | Description |
|---|---|---|---|
subject | string | Yes | Ticket subject. Supports templating. |
description | string | No | Ticket body. Supports templating. |
priority | "low" | "medium" | "high" | "urgent" | No | Ticket priority. Defaults to "medium". |
tags | string[] | No | Tags to apply. Defaults to []. |
HTTP Webhook
Makes an HTTP request to an external URL.
| Config field | Type | Required | Description |
|---|---|---|---|
url | string (URL) | Yes | Destination URL. |
method | "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | No | HTTP method. Defaults to "POST". |
headers | Record<string, string> | No | Extra request headers. Defaults to {}. |
bodyTemplate | string | No | JSON body template. Supports {{variable}} substitution. |
Example config
{
"type": "action.http-webhook",
"config": {
"url": "https://hooks.example.com/notify",
"method": "POST",
"headers": { "Authorization": "Bearer my-token" },
"bodyTemplate": "{\"email\": \"{{contact.email}}\"}"
}
}
Run Agent
Runs an AI agent with a custom prompt and returns the agent's response.
| Config field | Type | Required | Description |
|---|---|---|---|
agentId | string | No | Agent to run. Uses team default if omitted. |
promptTemplate | string | Yes | Prompt sent to the agent. Supports {{variable}} templating. |
model | string | No | Model to use. Defaults to "gpt-5-mini". |
systemPrompt | string | No | Optional system prompt override. |
Update Contact
Updates fields on an existing contact.
| Config field | Type | Required | Description |
|---|---|---|---|
contactIdPath | string | Yes | Path to the contact ID in the run context. Defaults to "trigger.contactId". |
name, first_name, last_name, email, phone, company_name | string | No | New field values. Support templating. |
assigned_to | string | No | Assign the contact to a team member. |
tags | string | No | Replace contact tags (comma-separated). |
custom_fields | string | No | JSON string of custom fields to merge. |
Slack Alert
Sends a message to a Slack channel.
| Config field | Type | Required | Description |
|---|---|---|---|
connectionId | string | No | Slack connection ID. Uses team default if omitted. |
channelId | string | Yes | Target Slack channel ID. |
channelName | string | No | Human-readable channel name (for display). |
messageTemplate | string | Yes | Message text. Supports {{variable}} templating. |
includeSubmissionData | boolean | No | Append form submission fields to the message. Defaults to false. |
MCP Tool
Calls a tool on an MCP server or configured team action.
Inline mode (call a tool on a connected MCP server):
| Config field | Type | Required | Description |
|---|---|---|---|
mode | "inline" | Yes | Set to "inline". |
connectionId | string | Yes | MCP server connection ID. |
toolName | string | Yes | Name of the tool to call. |
parameters | Record<string, string> | No | Tool parameters. Support templating. |
timeoutMs | number | No | Request timeout in milliseconds. |
Action mode (call a team action):
| Config field | Type | Required | Description |
|---|---|---|---|
mode | "action" | Yes | Set to "action". |
actionId | string | Yes | Team action ID. |
parameters | Record<string, string> | No | Action parameters. Support templating. |
Team Action
Runs a configured team action (shorthand for MCP Tool in action mode).
| Config field | Type | Required | Description |
|---|---|---|---|
actionId | string | Yes | Team action ID. |
parameters | Record<string, string> | No | Parameters. Support templating. Defaults to {}. |
Data nodes
Data nodes fetch records from ChatDrift for use in downstream nodes.
Fetch Conversations
Fetches recent conversations for analysis or routing.
| Config field | Type | Required | Description |
|---|---|---|---|
hoursBack | number | No | Lookback window in hours. Defaults to 24. |
status | "unassigned" | "active" | "completed" | "all" | No | Filter by conversation status. Defaults to "all". |
limit | number (1–200) | No | Max conversations to fetch. Defaults to 50. |
Example config
{
"type": "data.fetch-conversations",
"config": {
"hoursBack": 24,
"status": "unassigned",
"limit": 50
}
}
AI nodes
AI nodes use a language model to generate text, extract data, or classify content.
AI LLM
Generates free-form text from a prompt.
| Config field | Type | Required | Description |
|---|---|---|---|
promptTemplate | string | Yes | Prompt text. Supports {{variable}} templating. |
systemPrompt | string | No | Optional system prompt. |
model | string | No | Model to use. Defaults to "gpt-5-mini". |
maxOutputTokens | number | No | Cap the response length. |
AI Extract
Extracts structured fields from text using a language model.
| Config field | Type | Required | Description |
|---|---|---|---|
inputField | string | Yes | Path to the text to extract from (e.g. "trigger.payload.message"). |
fields | {name: string, description: string}[] | Yes | Fields to extract. At least 1. |
model | string | No | Model to use. Defaults to "gpt-5-mini". |
Example config
{
"type": "ai.extract",
"config": {
"inputField": "trigger.payload.message",
"fields": [
{ "name": "email", "description": "The visitor's email address" },
{ "name": "company", "description": "The visitor's company name" }
]
}
}
AI Classify
Classifies text into one of a list of categories.
| Config field | Type | Required | Description |
|---|---|---|---|
inputField | string | Yes | Path to the text to classify. |
categories | string[] | Yes | At least 2 category names. |
model | string | No | Model to use. Defaults to "gpt-5-mini". |
Example config
{
"type": "ai.classify",
"config": {
"inputField": "trigger.payload.message",
"categories": ["billing", "technical", "general"]
}
}
Control nodes
Control nodes change the flow of execution: branching, looping, waiting, or routing.
Condition
Branches the workflow based on a field value.
| Config field | Type | Required | Description |
|---|---|---|---|
field | string | Yes | Path to the value to test (e.g. "ai_classify.result"). |
operator | "equals" | "not_equals" | "contains" | "not_contains" | "gt" | "lt" | "is_empty" | "is_not_empty" | Yes | Comparison operator. |
value | string | No | Value to compare against (not needed for is_empty/is_not_empty). |
Contact Attribute Check
Branches based on a contact's current attribute value. Fetches the contact's live data at run time.
| Config field | Type | Required | Description |
|---|---|---|---|
contactIdPath | string | Yes | Path to the contact ID. Defaults to "trigger.contactId". |
attributeName | string | Yes | Contact attribute to check (e.g. "tags", "company_name"). |
operator | string | Yes | Same operators as Condition. |
value | string | No | Value to compare against. |
Wait / Delay
Pauses the workflow for a fixed duration.
| Config field | Type | Required | Description |
|---|---|---|---|
duration | number (≥1) | Yes | How long to wait. |
unit | "seconds" | "minutes" | "hours" | "days" | Yes | Unit of time. |
Example config
{
"type": "control.wait",
"config": { "duration": 1, "unit": "days" }
}
Human Approval
Pauses the workflow and waits for a human to approve or reject. Optionally notifies team members by email. The workflow resumes automatically once a decision is made — either by a human in the dashboard or by an external agent using submit_approval.
| Config field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | The question or context shown to the approver. Supports {{variable}} templating. |
notifyEmails | string[] | No | List of email addresses to notify. Defaults to []. |
For Each
Runs a sub-workflow once per item in an array — in parallel up to concurrency.
| Config field | Type | Required | Description |
|---|---|---|---|
itemsPath | string | Yes | Path to the array to iterate (e.g. "fetch_conversations.conversations"). |
body | WorkflowGraph | Yes | The sub-workflow to run per item. |
concurrency | number (1–10) | No | Number of parallel runs. Defaults to 5. |
maxItems | number (1–1000) | No | Cap on items to process. Defaults to 1000. |
Merge
Waits for parallel branches to complete and merges their outputs.
| Config field | Type | Required | Description |
|---|---|---|---|
mode | "all" | "any" | No | "all" waits for all branches; "any" continues after the first. Defaults to "all". |
combine | "object" | "array" | No | How to combine branch outputs. Defaults to "object". |
AI Router
Uses a language model to pick one of several named branches based on an instruction.
| Config field | Type | Required | Description |
|---|---|---|---|
instruction | string | Yes | Prompt that tells the LLM how to choose a route. |
inputTemplate | string | No | Additional context to include in the prompt. |
routes | {key: string, description: string}[] | Yes | At least 2 named routes. |
fallbackRoute | string | No | Route to take if the LLM cannot decide. |
model | string | No | Model to use. Defaults to "gpt-5.4-mini". |
Wait for Handoff Reply
Pauses the workflow after a human handoff and resumes when the first staff reply is sent.
| Config field | Type | Required | Description |
|---|---|---|---|
timeoutMinutes | number | No | Abandon wait after this many minutes. Defaults to 5. |
bridgeIdPath | string | No | Path to the handoff bridge ID in context. |
Pre-built templates
ChatDrift ships 9 templates you can load as a starting point from the visual editor.
| Template | Category | Trigger | Description |
|---|---|---|---|
| AI Triage Ticket | Support | Form Submitted | Classifies the submission's intent and creates a low or high priority ticket accordingly. |
| Welcome Contact | Contacts | Webhook Received | Sends an immediate welcome message, waits 1 day, then sends a follow-up. |
| Lead Qualification | Sales | Form Submitted | Extracts contact details, conditionally runs an AI agent for qualified leads, sends a message otherwise. |
| KB Agent Reply | Support | Ticket Created | Runs an AI agent to draft a knowledge-base reply and posts it via HTTP webhook to your helpdesk. |
| Human-Approved Refund | Support | Ticket Created | Generates a refund recommendation with an LLM, pauses for human approval, then calls an external API. |
| Scheduled NPS Survey | Engagement | Schedule (weekly) | Generates a personalised NPS message with an LLM and sends it to contacts. |
| Slack Form Alert | Lead Gen | Form Submitted | Posts every form submission to a Slack channel immediately. |
| MCP Form Email | Lead Gen | Form Submitted | Uses an MCP tool to send an email notification for each form submission. |
| Daily Digest | Engagement | Schedule (daily 8am) | Fetches yesterday's conversations, summarises them with an LLM, and posts the digest to Slack. |