Skip to main content

Actions — the THEN blocks

An action is a step that does something: sends a message, updates a conversation, writes to your CRM, calls an external API, sends an email, or transforms a value for the next block.

Actions carry the teal THEN badge. You add them from the block picker: drag a connector out of any block and release it on empty canvas.

The full list

ActionGroupWhat it does
Reply MessageConversationsSends a message to the customer, and can pause the flow until they answer.
Private NoteConversationsAdds an internal note that the customer never sees.
Change ConversationConversationsHands over to a human, a team, or the waiting line; labels, prioritizes, resolves, renames, and sets conversation attributes.
End SessionConversationsReleases the conversation from Studio, optionally resolving it.
WaitFlowPauses this path for 1–15 seconds.
Save as VariableFlowStores a value permanently under var.* for future runs.
Contact UpdateCRMWrites to fields on the contact record.
Customer RecordCRMCreates or updates a CRM object record under a customer.
HTTP RequestExternalCalls an external API, optionally capturing the response.
Send EmailExternalSends an email from an inbox or from the Teloring system sender.
CodeToolsRuns a small sandboxed JavaScript transform.
Date and TimeToolsGets, formats, adds, subtracts, compares, extracts, or rounds dates.
Send Teloring NotificationToolsAlerts agents inside Teloring — bell, sound, email, and browser push.
Play SoundVoicePlays an audio prompt to a caller.
Wait / PauseVoicePauses the call briefly.
IVR MenuVoicePlays a menu and routes by keypad digit.
Forward to AgentVoiceRings an agent in the browser and bridges the call.
Forward to External PhoneVoiceTransfers the call to an outside number.
Hang UpVoiceEnds the call.

Branching blocks — Condition If/Else, Business Hours, Agent Availability — carry the amber IF badge and are documented in Conditions.

Things that are true for every action

  • Text fields accept variables. Type {{ or drag a variable in from the Available Variables section. See Variables.
  • Outputs become variables. Everything an action produces is available to every block below it.
  • Fan-out runs everything. If an action has three connectors leaving it, all three paths run.
  • A failed action stops its own path, not the whole flow — other branches keep going.

Reply Message

Sends a message to the customer in the conversation, exactly as if an agent had typed it. It goes out on whichever channel the conversation is on — WhatsApp, email, SMS, Telegram, live chat, and so on.

This is also the block that turns a flow into a conversation: switch Wait for client response on and the flow pauses until the customer answers.

Messaging flows only.

Properties

PropertyWhat it doesDefault
Conversation IDWhich conversation to send in. Leave the default to reply in the conversation that triggered the flow.{{conversation.id}}
Message (required)The text to send. Use variables for personalization.Empty
Wait for client responsePauses this path until the customer replies. Their reply becomes the new {{message.content}} and is also available as {{client_reply.content}}.Off
Wait timeout (minutes)How long to wait before giving up. 0 means no timeout — the flow keeps waiting. Teloring holds a waiting flow for up to 30 days either way. Appears only when waiting is on.0

Reply Message configuration

Outputs

VariableHolds
{{reply.message_id}}The sent message
{{reply.conversation_id}}Where it was sent
{{reply.sent_at}}When
{{reply.status}}Send status
{{client_reply.content}}What the customer replied (when waiting)
{{client_reply.content_type}}The reply's type
{{client_reply.message_id}} · {{client_reply.received_at}}Reply message and timestamp

How waiting behaves

  • While the flow waits, the conversation stays in the Studio Bot queue.
  • The customer's reply is consumed by the waiting flow — it does not start a second run of the same flow.
  • After the wait, you can test the answer with either {{message.content}} or {{client_reply.content}}; they hold the same text.
  • If a condition after a wait matches no branch and there is no ELSE branch, the flow keeps waiting at that condition and re-evaluates on the customer's next message. Add an ELSE branch, or an End Session block, so a customer can never get stuck in the flow.
  • If the timeout expires, the run ends as timed_out.
tip

Ask one question per Reply Message. Two questions in one message get one answer, and your condition has nothing clean to match.


Private Note

Adds an internal note to a conversation. It appears in the conversation timeline for agents and is never sent to the customer, on any channel.

Properties

PropertyWhat it doesDefault
Conversation IDWhich conversation gets the note.{{conversation.id}}
Private noteThe note text. Variables are supported.Empty

Outputs

VariableHolds
{{private_note.message_id}}The note
{{private_note.conversation_id}}Where it was added
{{private_note.created_at}} · {{private_note.status}}When, and the result

Good uses: record what a bot collected before handing over, paste an order status pulled from an API, or leave the reason a conversation was escalated.


Change Conversation

Updates the conversation — and, most importantly, is where you hand it over to a human: one specific agent, a whole team, or the waiting line.

Properties

PropertyOptionsWhat it does
Conversation IDText / variableWhich conversation to update. Defaults to {{conversation.id}}.
Human interventionOn / OffHands the conversation to a person. Studio stops owning it, so the next customer message goes to the agent instead of back into the flow.
Hand over toWaiting in line (next available agent) · A specific agent · A teamAppears when Human intervention is on.
AgentAgent pickerAppears when handing over to a specific agent.
TeamTeam pickerAppears when handing over to a team. A marks a team that auto-assigns to an online member; the number in brackets is how many agents it has.
Labels modeAdd labels · Replace labels · Remove labelsHow the labels below are applied.
LabelsOne label per lineThe labels to add, set, or remove.
PriorityNo change · Low · Medium · High · UrgentSets the conversation priority.
StatusNo change · Open · Pending · ResolvedSets the conversation status.
FlagNo change · None · Important · Follow upSets the conversation flag.
SubjectText / variableRenames the conversation.
Conversation attributesAttribute picker + valueSets your account's Conversation Attributes on this conversation. Pick the attribute, type the value — variables allowed. See below.

Change Conversation configuration

Outputs

VariableHolds
{{conversation.status}}Result of the update
{{conversation.updated_fields}}Which fields changed
{{conversation.handover}}queue, agent, team, or empty
{{conversation.handover_agent_id}}The agent it was handed to — for a team handover, the member who was auto-assigned, or empty if it waits in line
{{conversation.handover_team_id}}The team it was handed to
{{conversation.handover_team_name}}That team's name
{{conversation.custom_attributes}}Every conversation attribute, as one object
{{conversation.custom_attributes.<api_id>}}One attribute — for example {{conversation.custom_attributes.reason_for_contact}}

Setting conversation attributes

Conversation Attributes are your account's own fields on a conversation — Reason for contact, Outcome, Order number. They live in this block rather than a block of their own, because they are fields on the conversation exactly like priority and subject.

Click Add field under Conversation attributes, pick an attribute, and give it a value. The value accepts variables, so a flow can classify a conversation from what it already knows:

FlowSets
A menu asks "what is this about?"Reason for contact = the button the customer pressed
A form starts the conversationOrder number = {{answers.order_number}}
An HTTP Request looks the customer upAccount tier = {{http.json.tier}}
The bot resolves the conversation itselfOutcome = Solved by bot
RuleBehavior
Values are validatedA value that is not one of a dropdown's options fails the block, so a flow can never write something the agent panel would refuse to show.
Deleted attributes are skippedAn attribute removed from Settings after the flow was built is ignored, and the block keeps running.
Other attributes are keptSetting one attribute never clears the rest.
Multi-selectSeparate values with commas or new lines.

The block outputs the new values, so every block below it — an HTTP Request above all — sees what was just written. Attributes are also available from the trigger, without this block, on Incoming Message, Incoming Call and Conversation Changed. See Variables.

Understanding Human intervention

SettingWhat happens
OffOnly the labels, priority, status, flag, and subject change. Studio keeps owning the conversation and later messages still run the flow.
On → A specific agentThe conversation is assigned to that agent and leaves the Studio Bot queue. If the conversation was on a team that agent does not belong to, the team is cleared.
On → A teamThe team takes ownership. If the team auto-assigns to an online agent, one of its online members receives it immediately; otherwise it waits in line and only members of that team can pull it with Get next. A resolved conversation is re-opened first.
On → Waiting in lineThe conversation is unassigned and dropped into the Waiting in line queue for whoever is free next. A resolved conversation is re-opened first, because a resolved conversation cannot wait in line.

Either way, the handover sticks: later messages on that conversation will not be pulled back into this flow — or into any other live flow. The handover is cleared automatically when the conversation is resolved, when the conversation is assigned to a specific agent, or when a flow runs End Session.

Two things to check on a team handover
  • Pick the team. If Hand over to is A team but no team is selected, the handover falls back to the plain waiting line. The editor flags the block while you are editing.
  • Deleting a team breaks the block. If the selected team is later deleted, the block fails at runtime rather than parking the conversation on a team that no longer exists. Review your live flows after deleting a team.
tip

Every customer-facing flow should have a route to a human. Wire an "I want to talk to someone" branch, or a fallback branch, into a Change Conversation block with Human intervention on.


End Session

Ends Studio's involvement with the conversation. The next message from that customer starts trigger matching from scratch, as if the flow had never run.

Properties

PropertyWhat it doesDefault
Conversation IDWhich conversation to release.{{conversation.id}}
Should we also resolve the conversation?Also marks the conversation resolved.Off

Outputs

VariableHolds
{{session.status}}Result
{{session.conversation_id}}The conversation
{{session.resolved}}Whether it was resolved too

End Session vs. Human intervention

UseWhen
End SessionThe bot has finished its job. Nobody in particular needs to act, and the next message should be able to start a flow again.
Change Conversation → Human interventionA person or a team needs to take this conversation now.

Wait

Pauses this path of the flow for a few seconds before continuing. Use it to space out messages so a bot feels less robotic.

Messaging flows only. Voice flows use Wait / Pause.

Properties

PropertyWhat it doesDefault
Wait duration (seconds)Between 1 and 15 seconds.3

Outputs

VariableHolds
{{wait.seconds}}How long it waited
info

Wait only holds up the branch it sits on. If the trigger also feeds another branch, that branch runs immediately — it does not queue behind the wait.


Save as Variable

Stores a value permanently, so later runs of the same flow can read it back. Ordinary variables live only for one run; a saved variable outlives it.

Properties

PropertyWhat it doesDefault
Variable keyThe name to store it under. Always inside the var. namespace. Dynamic keys are allowed, for example var.{{contact.phone}}.address.var.my_value
ValueWhat to store. Variables are supported.{{message.content}}
Value typeText · Number · Boolean · JSONText
Overwrite existing variableWhether an existing value with the same key may be replaced.On

Outputs

VariableHolds
{{saved_variable.key}}The normalized key that was written
{{saved_variable.value}}The stored value
{{saved_variable.status}}Result

How saved variables work

  • They are per flow. Two flows can each have their own var.counter without colliding.
  • They are loaded into every run of that flow, so {{var.my_value}} is available from the first block onward.
  • Keys are forced into the var. namespace, so a saved value can never overwrite a system, contact, conversation, or message variable.
  • Unsupported characters in a key become underscores.
  • Review and delete them in ⚙ Flow Settings → Saved variables.

Good uses: remember a per-customer preference keyed by phone number, store the last synced ID from an external system, or keep a running counter.


Contact Update

Writes to fields on the contact record — the person, not the company.

Properties

PropertyWhat it doesDefault
Contact IDWhich contact to update.{{contact.id}}
Fields to updateRows of field → value. The field name is a dropdown of the contact fields your account actually defined in the Field Editor. A field already used in one row disappears from the other dropdowns. Values support variables.Empty

Outputs

VariableHolds
{{contact.status}}Result
{{contact.updated_fields}}Which fields were written
note

Protected system fields cannot be written by a flow. If a field you expect is missing from the dropdown, add it in the contact Field Editor first — see CRM and Customers.


Customer Record

Creates or updates a CRM object record under a customer — a service call, an order, a note, a contract, or any other object your account has defined.

Properties

PropertyOptionsWhat it does
OperationAdd new record · Edit existing recordWhether to create or update.
Customer IDText / variableWhich customer the record belongs to. Defaults to {{customer.id}}.
Object type (required)Dropdown of the account's enabled CRM objectsWhich object this record is. The field list below follows this choice.
Record IDText / variableWhich record to edit. Appears only for Edit existing record.
Record fieldsRows of field → valueThe dropdown lists the real fields of the selected object type. Disabled until an object type is chosen. Values support variables.

Customer Record configuration

Outputs

VariableHolds
{{record.status}}created or updated
{{record.id}}The record
{{record.schema_id}}The object type
{{record.customer_id}}The customer

Values are validated against the object's field definitions before anything is written, so a bad value fails the block instead of corrupting the record.

tip

Creating a record here fires the Customer record trigger. That is useful for chaining flows — but watch out for a flow that triggers itself.


HTTP Request

Sends data to an external system, or fetches data from one. This is the general-purpose bridge between Teloring and the rest of your stack.

Properties

PropertyOptionsWhat it does
MethodGET · POST · PUT · PATCH · DELETE · COPY · HEAD · OPTIONSThe HTTP method.
URL (required)Text / variableThe full URL. Variables are supported, for example https://api.example.com/orders/{{contact.id}}.
Request headersKey/value rowsAny headers you need. Content-Type, Cache-Control, User-Agent, and Accept are offered as presets. Values support variables.
Body typeNone · JSON · Form dataWhat to send in the body.
JSON bodyText areaAppears for JSON. Must be valid JSON.
Form fieldsKey/value rowsAppears for Form data. Values support variables.
Request timeout (seconds)1–60How long to wait for the server.
Capture response for next actionsOn / OffSee below.

HTTP Request configuration

Capture response — on or off?

SettingBehaviorUse when
OffFire-and-forget. The request is queued and sent in the background; the flow continues immediately.You are notifying an external system and do not need its answer.
OnThe flow waits for the response and exposes it as variables.You need the answer — an order status, a price, a customer ID.

Outputs

VariableHolds
{{http.status}}Send status
{{http.task_id}}Background job ID, when capture is off
{{http.status_code}}HTTP status code, for example 200
{{http.ok}}true for a 2xx response
{{http.content_type}}The response content type
{{http.body}}The raw response body
{{http.json}}The response parsed as JSON
{{http.headers}}The response headers
{{http.error}}The error, if the call failed

When the response is a JSON object, its fields are also flattened into their own variables — {{http.json.order_id}}, {{http.json.customer.name}}, and so on.

Variables inside a JSON body

Studio is type-aware when it fills a JSON body:

  • A variable that fills a whole value — written bare ("answers": {{answers.list}}) or as a complete quoted string ("answers": "{{answers.list}}") — keeps its real JSON type. Arrays stay arrays, numbers stay numbers, objects stay objects.
  • A variable inside a longer string ("greeting": "Hi {{contact.name}}!") is substituted as text, with quotes and special characters safely escaped.
  • A variable that resolves to nothing is left as-is.

The editor validates the JSON while you type. Invalid JSON turns the box red and puts a warning badge on the block; you can keep editing, but fix it before publishing.

Security

Studio only calls public http:// and https:// addresses. Localhost, private networks, loopback, link-local, and cloud metadata addresses are blocked, so a flow can never be used to reach inside infrastructure.


Send Email

Sends an email. This is a pure send — it does not create a conversation, a contact, or a message in any inbox timeline, so you can email a manager, a supplier, or an internal alias without polluting an inbox.

Properties

PropertyOptionsWhat it does
Send fromOne of my email inboxes · Teloring system senderWho the email comes from.
Email inboxDropdown of connected email inboxesAppears for the inbox option. Any connected email inbox can send — conversation inboxes and sending-only inboxes alike.
System senderRead-only noticeAppears for the system option, showing the address that will be used.
To (required)Text / variableOne or more addresses. Defaults to {{contact.email}}.
CC · BCC · Reply-ToText / variableOptional.
Subject (required)Text / variableThe subject line.
Body formatPlain text · HTMLHow the body is written.
Body (required)Text areaThe email content. Variables are supported.
Custom headersKey/value rowsOptional technical headers. X-Teloring-Flow, X-Campaign, X-Priority, and List-Unsubscribe are offered as presets.

Send Email configuration

Outputs

VariableHolds
{{email.status}}sent, failed, or test
{{email.message_id}}The sent message
{{email.from}} · {{email.to}} · {{email.subject}}What was sent, and to whom
{{email.provider}}Which transport delivered it
{{email.error}}The error, if it failed

Recipients and limits

  • To, CC, BCC, and Reply-To accept several addresses separated by commas, semicolons, or new lines, and understand the Name <address@example.com> form.
  • Every address is validated and de-duplicated. 25 recipients in total, at most.
  • At most 10 custom headers. Addressing and threading headers (From, To, Cc, Bcc, Reply-To, Subject, Message-ID, Content-Type, …) are set in the fields above and cannot be overridden here.
  • Whichever body format you choose, both a text and an HTML part are sent, so the email renders everywhere.
caution

Replies to the Teloring system sender do not come back into Teloring. If you want answers, either send from one of your own inboxes or set a Reply-To.

note

A Test Run resolves the sender and validates everything, but sends nothing. The block reports email.status = test.


Code

Runs a small JavaScript transform and returns a value for the blocks below it. Use it for the things a text field cannot do: cleaning a phone number, splitting a name, reformatting an ID, picking one item out of a list.

Properties

PropertyWhat it does
JavaScript code (required)The code to run. It must return a value.

New blocks start with a working example:

const phone = "{{contact.phone}}";
const cleanNumber = phone.replace(/^\+/, '');
return cleanNumber;

Reading variables

Two ways, both fine:

// 1 — substituted before the code runs
const name = "{{contact.name}}";

// 2 — read from the frozen variables object
const phone = variables["contact.phone"];

Outputs

VariableHolds
{{code.status}}Result
{{code.result}}The returned value, with its type preserved
{{code.result_text}}The returned value as text
{{code.error}}The error, if the code failed

What the sandbox allows

The Code block runs isolated, with a memory cap and a short time limit. It is meant for data manipulation only:

AllowedBlocked
String, number, array, object, date, and regex operationsfetch, XMLHttpRequest, WebSocket — no network
The variables object and any {{variable}} you substituterequire, import, process — no modules, no environment
Returning any JSON-serializable valueeval, Function, WebAssembly

Code that does not return a value fails the block on purpose, so the flow never continues with missing data. To call an external service, use HTTP Request.


Date and Time

Calculates and formats dates. Every operation is timezone-aware.

Properties

PropertyOptionsWhat it does
OperationGet current date/time · Add time · Subtract time · Format date · Extract part · Time between dates · Round dateWhat to calculate.
Input dateText / variableThe date to work on, in ISO form. Leave empty for "now".
Second dateText / variableThe other date. Appears for Time between dates.
AmountNumberHow much to add or subtract. Appears for Add and Subtract.
UnitSeconds · Minutes · Hours · Days · WeeksThe unit for Amount.
PartDate · Time · Year · Month · Day · Hour · Minute · WeekdayWhich piece to pull out. Appears for Extract part.
FormatTextThe output pattern, for example %Y-%m-%d %H:%M:%S. Appears for Format date.
TimezoneTextThe timezone the calculation runs in. Defaults to Asia/Jerusalem.

Outputs

VariableHolds
{{datetime.status}}Result
{{datetime.result}}The calculated value
{{datetime.result_text}}The value as text
{{datetime.date}} · {{datetime.time}}Date part and time part
{{datetime.timestamp}}Unix timestamp

Good uses: work out a follow-up date three days out, format a timestamp for a customer-facing message, or measure how long a conversation has been open before deciding to escalate.


Send Teloring Notification

Alerts agents inside Teloring — the notification bell, a sound, an email, and a browser push. Use it for anything the two built-in notification types do not cover: a new lead, an analytics threshold, an SLA about to breach, a form submission, a VIP customer writing in.

This is the flexible half of Notifications. The profile page ships two ready-made types ("a conversation was assigned to me" and "a new message arrived") so an agent who never opens Studio still gets something useful. Everything beyond that is built here.

The flow chooses what and who. The recipient chooses how.

This block decides the text and the recipients. It never decides how the notification reaches them — that stays with each agent, in their own profile.

An agent who enabled only the bell gets a bell entry. A colleague on the same notification who enabled all four gets a sound, an email, a push, and a bell entry. An agent with notifications switched off — or with Studio notifications switched off — gets nothing at all, and the flow carries on normally.

Properties

PropertyOptionsWhat it does
Send to (required)Specific agents · The agent assigned to this conversation · Everyone in a teamWho is notified.
AgentsCheckbox list of agentsAppears for Specific agents. Human agents only — an AI Agent has no inbox to notify.
TeamDropdown of teamsAppears for Everyone in a team. Every member is notified.
Conversation IDText / variableAppears for The agent assigned to this conversation. Defaults to {{conversation.id}}.
Message (required)Text areaThe text agents see. Variables are supported — New contact {{contact.name}} created!
Extra detailsText areaAn optional second line, shown in the bell list, the email, and the browser push.
Clicking the notification opensThe conversation from this flow · Nothing — text only · A specific Teloring pageWhere the notification links to.
Teloring pageText / variableAppears for the specific-page option. A path inside Teloring, such as /dashboard/customers.

Send Teloring Notification configuration

Outputs

VariableHolds
{{notification.status}}sent, no_recipients, test_mode, or failed
{{notification.recipients}}How many agents were targeted
{{notification.delivered}}How many actually received something, after their own settings were applied
{{notification.message}}The final text, with variables resolved
{{notification.error}}The error, if it failed

recipients and delivered are usually the numbers you want when debugging. recipients: 3, delivered: 0 means the flow found three agents and none of them had Studio notifications switched on.

Understanding "Send to"

OptionResolves toWhen nobody matches
Specific agentsExactly the agents you ticked.The block reports no_recipients.
The agent assigned to this conversationWhoever currently owns the conversation.An unassigned conversation has no owner, so the block completes with no_recipients. This is not an error — the flow continues.
Everyone in a teamEvery member of the chosen team, at the moment the block runs.An empty or deleted team reports no_recipients.

Limits and safety

  • External links are impossible. The Teloring page field only accepts a path inside Teloring. An absolute URL is dropped, so a notification can never be turned into a link to an outside site.
  • Message is trimmed to 160 characters and Extra details to 600.
  • The text is displayed as plain text everywhere it appears, including inside the email.
  • An empty Message fails the block. As everywhere in Studio, a variable that cannot be resolved is left visible ({{contact.name}}) rather than silently blanked, so you can spot the mistake.
  • The same notification cannot reach the same agent twice within 60 seconds.
note

A Test Run resolves the recipients and the text and validates everything, but notifies nobody. The block reports notification.status = test_mode. Testing a flow never rings real agents.

Example — tell the Sales team about a new lead

  1. Trigger: Customer Changed → created
  2. Condition: If/Else → {{customer.new.lifecycle_stage}} equals lead
  3. Then: Send Teloring Notification
    • Send to: Everyone in a team → Sales
    • Message: New lead: {{customer.new.name}}
    • Extra details: Phone {{contact.phone}} · Source {{customer.new.source}}
    • Clicking the notification opens: A specific Teloring page → /dashboard/customers

Every member of Sales who has Studio notifications enabled is alerted, each through their own chosen methods.

Next