Flow recipes
Complete, working flows you can build in a few minutes each. Every recipe lists the blocks, their settings, and the reasoning behind them.
Every recipe below can also be described to Hermes in a sentence — "qualify a new WhatsApp lead and send them to sales or support" — and built for you. The recipes are still worth reading: they show what a good flow looks like, which makes it easy to check the AI's work.
| Recipe | Trigger | Good for |
|---|---|---|
| Instant welcome reply | Incoming Message | Any new inbox |
| After-hours auto-reply | Incoming Message | Teams with fixed hours |
| Qualify and route a new lead | Incoming Message | Sales and support split |
| Escalate an unhappy customer | Conversation Changed | Retention |
| Push a new lead into an external CRM | Form filled | Integrations |
| Start a conversation from an external system | Incoming webhook | Order and delivery updates |
| Daily morning summary | Scheduled Time | Managers |
| Alert a manager when a metric slips | Analytics Alert | Operations |
| Phone menu with agent transfer | Incoming Call | Voice |
1. Instant welcome reply
Answer within a second, so nobody waits in silence.
Incoming Message (Inboxes: WhatsApp)
└─ Reply Message
└─ End Session
| Block | Settings |
|---|---|
| Incoming Message | Tick your WhatsApp inbox. |
| Reply Message | Hi {{contact.name}}! Thanks for contacting Acme. One of our team will be with you shortly. · Wait for client response: off |
| End Session | Resolve the conversation: off |
Why End Session? Without it, Studio keeps owning the conversation and it sits in the Studio Bot queue. End Session releases it so it appears in Waiting in line for an agent to pick up.
{{contact.name}} is empty for a first-time contact on some channels. Either write a greeting that reads well without it, or branch on contact.name with the exists operator.
2. After-hours auto-reply
Say something useful when you are closed, and stay quiet when you are open.
Incoming Message
└─ Business Hours
├─ Open ──── (nothing — let agents handle it)
└─ Closed ── Reply Message ── End Session
| Block | Settings |
|---|---|
| Incoming Message | Leave inboxes empty to cover every channel. |
| Business Hours | Pick the schedule you created in Settings → Business Hours. |
| Reply Message (Closed) | Thanks for your message! Our team is offline right now. We're open Sunday–Thursday, 09:00–18:00, and will reply first thing. |
| End Session | Resolve: off |
Leaving the Open port unconnected is deliberate — during working hours the flow should do nothing at all and let agents reply normally.
3. Qualify and route a new lead
Ask one question, then send the conversation to the right team with the right label.
Incoming Message
└─ Reply Message (wait for reply)
└─ Condition If/Else
├─ Sales ───── Change Conversation (label: sales, hand over to queue)
├─ Support ─── Change Conversation (label: support, hand over to queue)
└─ Else ────── Reply Message "Sorry, I didn't catch that…"
| Block | Settings |
|---|---|
| Reply Message | Hi! Are you contacting us about **sales** or **support**? Just reply with one word. · Wait for client response: on · Wait timeout: 60 |
| Condition If/Else | Match mode: First match only · Add ELSE branch: on |
| — IF 1 | Label Sales · Value message.content · Operator contains · Compare as Text · Compare to sales |
| — IF 2 | Label Support · Value message.content · Operator contains · Compare as Text · Compare to support |
| Change Conversation (Sales) | Labels mode: Add · Labels: sales · Human intervention: on · Hand over to: Waiting in line |
| Change Conversation (Support) | Same, with the support label. |
| Reply Message (Else) | Sorry, I didn't catch that. Please reply with "sales" or "support". · Wait for client response: on |
Why contains and not equals? People type "sales please" and "I need SALES". contains is not case-sensitive and matches inside a sentence.
The ELSE loop. The ELSE branch asks again and waits again, so the customer gets another chance. Consider adding a Save as Variable counter, or a third strike that hands over to a human, so a confused customer is never stuck.
4. Escalate an unhappy customer
React the moment AI detects frustration.
Conversation Changed (AI Signals: Feelings / emotion detected)
└─ Condition If/Else
└─ Negative ── Change Conversation (priority: urgent, flag: important)
└─ Private Note
└─ Send Email
| Block | Settings |
|---|---|
| Conversation Changed | AI Signals: Feelings / emotion detected. Leave the other filters on any. |
| Condition If/Else | IF Negative · Value conversation.customer_emotion · Operator less than · Compare as Number · Compare to 3 |
| Change Conversation | Priority: Urgent · Flag: Important · Human intervention: on · Hand over to: Waiting in line |
| Private Note | ⚠️ AI detected negative sentiment ({{conversation.customer_emotion}}). Signal: {{ai.message}} |
| Send Email | To your team lead · Subject Escalation: {{contact.name}} · Body includes {{conversation.id}} and {{ai.message}} |
5. Push a new lead into an external CRM
Send every form submission straight to another system, and record the result.
Form filled (Form: Contact us)
└─ HTTP Request (capture response: on)
└─ Condition If/Else
├─ Success ── Save as Variable ── Private Note
└─ Else ───── Send Email (alert the admin)
| Block | Settings |
|---|---|
| Form filled | Pick the specific form. |
| HTTP Request | Method POST · URL your CRM endpoint · Header Content-Type: application/json · Body type JSON · Capture response on · Timeout 15 |
| Condition If/Else | IF Success · Value http.ok · Operator equals · Compare as Boolean · Compare to true |
| Save as Variable | Key var.{{contact.id}}.crm_id · Value {{http.json.id}} · Type Text |
| Private Note | Lead synced to CRM as {{http.json.id}}. |
| Send Email (Else) | To your admin · Body includes {{http.status_code}} and {{http.error}} |
JSON body:
{
"name": "{{answers.full_name}}",
"email": "{{answers.email}}",
"phone": "{{answers.phone}}",
"source": "{{sourceParams.utm_source}}",
"answers": {{answers.list}},
"teloring_contact_id": "{{contact.id}}",
"teloring_execution_id": "{{system.execution_id}}"
}
Note the unquoted {{answers.list}}. Because the variable fills a whole value, Studio inserts the real array instead of a string. See Variables in a JSON body.
6. Start a conversation from an external system
Let your order platform tell a customer their delivery is on the way.
Incoming webhook
└─ Reply Message
└─ Contact Update
| Block | Settings |
|---|---|
| Incoming webhook | Copy the URL · Allowed methods POST · Learn next request on, then send one real request. |
| Reply Message | Conversation ID {{webhook.body.conversation_id}} · Message Good news {{contact.name}} — order {{webhook.body.order_id}} is out for delivery. Track it here: {{webhook.body.tracking_url}} |
| Contact Update | Field last_order_status → {{webhook.body.status}} |
Getting the conversation ID. A webhook flow has no conversation of its own, so {{conversation.id}} is empty. Either have the caller send a conversation ID in the payload, as above, or look it up with an HTTP Request first.
7. Daily morning summary
A private note in a chosen conversation, or an email, every working morning.
Scheduled Time (Sun–Thu, 08:30, Asia/Jerusalem)
└─ HTTP Request (capture response: on)
└─ Send Email
| Block | Settings |
|---|---|
| Scheduled Time | Five rows: Sunday–Thursday, hour 8, minute 30, timezone Asia/Jerusalem. |
| HTTP Request | Fetch whatever numbers you want to report. Capture response on. |
| Send Email | To the team · Subject Morning summary — {{datetime.result}} · Body built from {{http.json...}} values |
Add a Date and Time block before the email (operation Format date, format %d/%m/%Y) if you want a friendly date in the subject.
8. Alert a manager when a metric slips
Wire an Analytics alert to a real notification, and let people know when it recovers.
Analytics Alert (Alerts: "Waiting conversations over 20")
├─ Alert ────── Send Email ── Change Conversation (priority: urgent)
└─ Recovered ── Send Email
| Block | Settings |
|---|---|
| Analytics Alert | Tick the alert you created in Analytics. |
| Send Email (Alert) | Subject 🔴 {{alert.name}} · Body {{alert.report_title}} is {{alert.current_value}} ({{alert.direction}} the threshold of {{alert.threshold}}) as of {{alert.crossed_at}}. |
| Send Email (Recovered) | Subject 🟢 {{alert.name}} recovered · Body {{alert.report_title}} is back to {{alert.current_value}}. |
The alert fires once per crossing, so you get one email — not one per minute while the number stays high.
9. Phone menu with agent transfer
A complete inbound call experience.
Incoming Call (record: on)
└─ Play Sound "Welcome to Acme. This call may be recorded."
└─ Business Hours
├─ Open ──── IVR Menu
│ ├─ 1 · Sales ──── Agent Availability
│ │ ├─ Online ── Forward to Agent ──┬─ Completed ─ HTTP Request
│ │ │ └─ Rejected ── Play Sound ─ Hang Up
│ │ └─ Offline ─ Play Sound ─ Hang Up
│ ├─ 2 · Support ── Forward to External Phone
│ ├─ Timeout ────── Play Sound ─ Hang Up
│ └─ Invalid ────── Play Sound ─ Hang Up
└─ Closed ── Play Sound ─ Hang Up
| Block | Settings |
|---|---|
| Incoming Call | Voice inbox: your number · Record this call: on |
| Play Sound (greeting) | WAV that includes the recording announcement. |
| Business Hours | Your schedule. |
| IVR Menu | Menu prompt WAV · Digits 1 · Sales, 2 · Support · Input timeout 7000 · Max attempts 2 |
| Agent Availability | Check Specific agents → your sales team · Consider online when At least one |
| Forward to Agent | Routing Any available agent · Ring timeout 30 |
| HTTP Request (Completed) | Log {{call.duration_seconds}}, {{call.talk_duration_seconds}}, {{call.agent_name}} to your system. |
| Forward to External Phone | Your support line, in international form. Bills credits. |
| Hang Up | Cause Normal clearing |
See Voice call flows for the full block reference.
Patterns worth reusing
| Pattern | How |
|---|---|
| Always give people an exit | Every waiting flow needs an ELSE branch or a handover, so a customer is never trapped. |
| Label before you hand over | A conversation that arrives in the queue already labelled and prioritized saves the agent a step. |
| Leave a note, not a mystery | A Private Note explaining what the bot collected is worth more to an agent than a clean timeline. |
| Log the IDs | Send {{conversation.id}}, {{contact.id}}, and {{system.execution_id}} to any external system you call. |
| Sticky-note your branches | Six months later, a sticky note explaining why a branch exists is the difference between improving a flow and rebuilding it. |
| One question per message | Two questions get one answer, and your condition has nothing clean to match. |
Next
- Troubleshooting — when a recipe does not behave.
- Testing & publishing — the safe way to release a flow.