Automate journeys with workflows
Multi-step automations with triggers, waits, branches, and goals
A workflow is a multi-step automation that contacts move through individually: they enter when something happens, steps run in order (sending messages, waiting, branching, updating data), and they exit when they finish, meet the goal, or stop qualifying. Think abandoned-quote follow-ups, post-purchase check-ins, or complaint escalations.
Manage them under Automation → Workflows (Owners and Admins).
Triggers: how contacts enter
- Contact performs an event — e.g. every
request_quoteenrolls the contact. Optionally restricted with a segment filter ("only if they're in Leads with no orders") and — for events that carry an inbox, see below — an inbox filter ("only in Support and Orders"). - Contact enters a segment — the moment segment rules start matching them.
Event triggers can be qualified further in the "Only enroll when…" panel — contacts filtered out here are never enrolled, so a "once ever" workflow can still catch them on a later matching event:
- Preset pickers — "Tag is added to a conversation" offers a tag picker ("only
complaintorurgent"); "Contact is linked to an entity record" offers entity and role pickers ("only Orders, only asbuyer"). - Property filters — match any property the triggering event carries: "where property
subjectcontains refund" onconversation_created, "where propertyattr_statusis any of paid, shipped" onentity_record_linked, or anything your own API events send. All filters must match. - Segment guards — the contact must be in at least one of the chosen segments, and/or must not be in any excluded ones, at the moment the event fires. (Hidden for "Contact is created" — a brand-new contact isn't in any segment yet; use a Filter step on contact attributes instead.)
Chatlane also records five lifecycle events automatically — each is a first-class choice in the Trigger dropdown (and usable in segments) out of the box:
contact_created— a new contact appears, from any source. Great for enrichment journeys (Trigger Agent with web search + an Update Contact action).conversation_created— a new conversation starts in an inbox (carries the inbox, so the inbox filter applies). Conversations created by broadcasts and workflow sends themselves are deliberately excluded, so a workflow can never re-trigger off its own message.conversation_tagged— a tag is added to a conversation, by a teammate or an AI agent. Combine with a property filter in segments ("where propertytagequalscomplaint") or use it directly as a trigger for escalation journeys.message_received— the contact sends a message, on any channel (carries the inbox, conversation, and channel; notes, call logs and outbound messages don't count). Use it as a trigger for reply-driven journeys — or, more commonly, as a goal event so any reply stops the follow-ups.entity_record_linked— a contact is linked to a custom entity record (an order, a booking…). The event carries the entity name, the record'sexternal_id, the contact'srole, and a snapshot of the record's attributes asattr_<name>properties — so "when a buyer is linked to an Order whoseattr_statusispaid" is a segment/property filter away.
A sixth system event, broadcast_sent, is recorded on every broadcast delivery. It isn't a dropdown preset, but typing its name as the trigger event works — useful for journeys that follow up on a broadcast. See Events and contact attributes for the full list and each event's properties.
Re-enrollment controls repeats: Once ever (one enrollment per contact, ever) or Every time (re-enroll on each trigger, with an optional cooldown of N days). A contact is never enrolled twice in the same workflow simultaneously.
Steps
Steps run top to bottom. Add them with Add workflow step:
- Send message — a templated message (contact variables supported) from a chosen inbox. Email bodies use a rich-text editor and keep their formatting; on other channels the same body is flattened to plain text. Pick a specific channel by name when an inbox has several of one type (two email addresses, two WhatsApp numbers), attach files, set a custom email From name for this step (supports variables; falls back to the channel's From name), and — on WhatsApp — pick an approved template for contacts outside the 24-hour messaging window.
- Trigger Agent — run one of your AI agents on the contact's conversation, exactly as if it fired on a live thread. The agent gets its full toolkit: knowledge files, send policy, and agent actions — so instructions like "summarise their situation, tag the conversation
at-risk, move it to Sales and assign it to [email protected]" actually perform those actions. Your instructions reach the agent as the latest customer turn and support variables (including{{response.KEY}}from an earlier webhook step). Choose whether the reply auto-sends, is created as a draft, is written as an internal note (nothing is sent to the customer), or inherits the agent's send policy for that inbox. - Wait — a fixed delay (minutes/hours/days), optionally followed by then wait for a time window: after the delay elapses, delivery holds until the next weekday slot (e.g. 9:00–18:00) in the contact's timezone — their
timezoneattribute (set via identify or an Update attributes step), falling back to the server timezone when absent or invalid. "Wait 2 days, then 9:00–18:00" means the follow-up never lands at 3 a.m. A zero-length wait with the window on reproduces the old "until time window" behaviour. - Update attributes — stamp attributes like
stage = contacted; other segments and workflows react to the change automatically. Values accept variables, including{{response.KEY}}from an earlier webhook step. - Webhook — call an external system with a templated HTTP request (method, URL, headers, query parameters and JSON body — the same editor and variable system as agent action webhooks, with a built-in test button). The JSON response is captured and exposed to every later step as
{{response.KEY}}using dot paths —{{response.order.status}},{{response.items.0.sku}}— so you can call your API, then write the answer to attributes, use it in a message, or feed it to an agent. With multiple webhook steps, give each one a response name (e.g.dataA) and its values become{{response.dataA.status}}vs{{response.dataB.status}}— unnamed steps share one namespace, where a later response overwrites matching keys. Not sure what the paths are? Run Test webhook — the response tab lists every placeholder the response produces, ready to copy into a later step. - Filter (continue or exit) — contacts matching the rules continue; everyone else exits here.
- True/False branch — evaluate rules and route contacts down a True or False path. Each path has its own steps (and can nest further branches). Paths run independently and don't rejoin — the workflow ends where each path ends.
Filter and branch rules go beyond attributes and events:
- Segment conditions — "is in / is not in VIP customers", checked live at the moment the step runs.
- Conversation conditions — status, read state, subject, tags, and assignee of the conversation that triggered this enrollment, also checked live. That's what makes reminder journeys work: wait 1 day → if the conversation is still unread and not tagged
handled→ escalate. If the enrollment wasn't triggered by a conversation event (a segment entry, or an event without a conversation), a conversation condition simply doesn't match.
Steps can also read the triggering event itself: {{event.PROPERTY}} resolves to any property it carried — {{event.tag}}, {{event.subject}}, {{event.attr_status}} — in message bodies, subjects, attribute values, webhook payloads, and agent instructions.
Which variables resolve where
Not every variable is available in every step. A placeholder that can't resolve is left in the text verbatim (the customer would see {{conversation.subject}} literally), so the Available variables panel under the steps lists only what your workflow can actually resolve — and once your trigger is chosen, the Trigger event group shows its real property names.
| Variable | When it resolves |
|---|---|
{{contact.*}} |
Always — every step, every trigger |
{{event.*}} |
Only event-triggered enrollments; keys = whatever that event carried. Empty for segment-entry |
{{response.*}} |
Any trigger, but only after a Webhook step has run |
{{sender.*}} |
Send message steps only (the sender is the team owner) |
{{conversation.*}}, {{inbox.*}} |
Trigger Agent instructions only — the one step templated with the conversation in hand. Send-message bodies are templated before the thread is resolved, so they don't resolve there |
{{entity.ATTRIBUTE}} |
Not available in workflows — it reads an entity-record conversation, and workflow sends always use contact conversations. Use {{event.attr_*}} from the Contact is linked to an entity record trigger instead |
Every step can also carry an only-if condition: if the contact doesn't match, that single step is skipped and the journey continues.
Choosing the channel
Send steps (including Trigger Agent) offer two channel modes:
- Contact's last-used channel (default) — reply where the customer last wrote to you: they messaged on WhatsApp, the follow-up goes out on WhatsApp. A fallback channel covers contacts with no message history, or whose last-used channel can't deliver (missing phone number, channel not on the inbox, or WhatsApp's 24-hour template rule).
- Fixed channel — always use a specific channel. The channel list shows only what the chosen inbox actually supports.
Auto-translation
When the step's inbox is covered by your team's Machine Translation integration (Team settings → Translation, attached per inbox), Send message steps offer "Automatically translate to the customer's language". To use it:
- Store each contact's language in a contact attribute holding an ISO 639-1 code, optionally with a region —
de,fr,pt-BR. Set it via the identify API (attributes: { "language": "de" }), an Update attributes step, or an agent's Update Contact action. - Tick the option on the step and pick that attribute (default:
language).
The body — and the subject, on email — is translated after variables resolve, so each recipient gets a personalised message in their own language. Contacts whose language is English (en, en-GB, en-US, …) are skipped entirely — messages are assumed to be written in English, so no translation call is made for them. It fails safe in every direction: a missing or non-ISO attribute value, an inbox without the integration, or a provider error all send the original text rather than blocking the journey.
Exits: how contacts leave
A contact's enrollment ends when:
- They finish the last step (completed)
- They perform a goal event — one or more event names; performing any of them (e.g.
place_orderorbook_call) exits immediately, so nobody gets a "still interested?" nudge after buying - They reply — add the built-in
message_receivedevent as a goal, and any inbound message from the contact ends the journey; no agent needed to stop follow-ups once a conversation turns live - They leave the trigger segment (if you enable exit when contact stops matching)
- A filter step doesn't match
Conversion goals
Set a conversion goal to measure whether the workflow works: a conversion event (e.g. place_order), an optional value property (e.g. order_total), and an attribution window. A conversion counts when the contact performs the event within the window of being sent a delivery from this workflow — no message, no credit, so the numbers stay honest. It doesn't matter how the enrollment ended: contacts who exited early on a goal event (or finished the steps) still convert if the event lands inside the window — the classic enquiry → quote (goal exit) → order (conversion) funnel counts. Each enrollment converts at most once, and the workflow page shows conversions, conversion rate, and total conversion value.
Draft, active, paused
The Active switch on the workflow editor controls its lifecycle:
- Draft — save and refine without enrolling anyone. New workflows start here.
- Active — the workflow enrolls and processes contacts. Activation requires at least one step.
- Paused — enrollments freeze exactly where they are (no new enrollments, no steps run) and resume from the same spot when you reactivate.
Structural edits require the workflow to be paused or draft — flip the switch off and save to pause-and-edit in one step. If a step is removed while contacts were waiting on it, those contacts exit gracefully (reason: step_removed) rather than doing something unexpected.
Monitoring
The workflow page shows enrollment and completion counts, conversion stats, a per-step funnel (done / skipped / failed at each step), and a table of every enrollment with its status, current step, and exit reason. Every step execution is logged per contact — including the exact message an AI agent composed.
The reference recipe
Abandoned-quote follow-up, end to end:
- Trigger: contact performs
request_quote· Re-enrollment: every time, 14-day cooldown - Goal event:
place_order· Conversion goal:place_order, valueorder_total, 14-day window - Steps: Wait 2 days → Filter: performed
place_orderexactly 0 times in last 7 days → Trigger Agent: "Write a friendly follow-up about their pending quote, referencing what they asked for."
Customers who buy during the wait exit at the goal and count as conversions. Everyone else gets a personalised nudge, in their language, in the same thread where they asked for the quote.