Guides

Omnichannel support that stays in one workspace

Voice rooms, inbox threads you can resolve, a flow and automation canvas, workspace run logs, and widgets in one Heliune workspace — with supervisor listen, whisper, and barge on the same call.

Heliune keeps the live call, the inbox thread, and the widget that started it in one workspace. You do not jump to a phone product to hear the customer, then a chat tool to finish the note. The objects are the same ones the team already opens: conversations, LiveKit rooms, flows, and automations.

Most “omnichannel” stacks still split those objects. The ticket lives in one queue. The recording lives in another. The bot that greeted the visitor has no idea the supervisor later whispered on the room. This page names what actually sits in the shell, what resolve does, and what a live flow records.

What sits in the shell

  • Calls with supervisor listen, whisper, and barge on the same LiveKit room.
  • One inbox for chat, email, and widget threads — open, snoozed, or resolved.
  • Live chat flows that record a run on the conversation they answered.
  • Automations you edit on a canvas — one trigger, then connected actions.
  • Workspace /logs: flow runs and automation history in one table.
  • Widgets you publish from the workspace and embed on your site.
  • Dashboards that use the same objects the team already works in.
  • The builder agent in the rail, next to the thread, not in a second tab.

Voice is a room, not a second product

A call is a LiveKit room with a recording. The person on the handset is an agent or a visitor. A supervisor joins the same room. Listen is subscribe-only and hidden: the supervisor hears the room and does not publish audio. Whisper and barge can publish. The agent does not lose the call when a lead joins.

That is the whole point of listen / whisper / barge. The lead does not steal the headset to hear what is happening. They stay on the same room the inbox thread already belongs to. When the call ends, the note is still that conversation — not a paste into another app.

Voice minutes sit on Pro and Business. Free and Starter keep the inbox, the widget, and the rail. If you only need the queue, you do not pay for rooms. If you take calls, the supervisor controls are the same workspace, not an add-on phone brand.

Resolve stays on the inbox thread

The inbox splits Open and Resolved. Open is everything that is not resolved — pending, snoozed, and open. Resolve leaves the open list. Reopen puts the thread back. Snooze keeps it out of the way without resolving it. Workspace unread totals skip resolved conversations. Opening a thread with unread clears that count. The document title shows the same unread, capped at 99+. Assignee on the inbox header is a person you pick on that thread — Unassigned, or a teammate. inbox.write is what enables the select. An automation that assigns writes the same assigneeId. They are not two queues.

When status flips to resolved, a matching automation can run on that conversation: assign a supervisor or a round-robin agent, add a VIP tag, open a follow-up task, or post a CSAT bot line. The trigger name is conversation.resolved. The object does not leave the workspace. Free workspaces have zero automations — the inbox still resolves; the engine has nothing to fire.

conversation.created is the other inbox event. A widget visitor’s first message opens a conversation; an automation can tag it or assign it before anyone clicks. Created and resolved are two moments on the same inbox row, not two products.

The engine also matches widget.handoff when a live flow records a handoff step, call.ended when a LiveKit room closes, and call.missed when nobody took the room. Those names live in the native catalog. An automation that watches call.ended can open a follow-up task on the same customer the inbox already knows. Do not invent a sixth trigger. If the catalog does not list it, the rail should not write it.

Native actions the engine already applies: assign.supervisor_queue, assign.round_robin (fewest open threads among agents, supervisors, and admins), tag.add vip, create.task (due in twenty-four hours), and send.csat_survey. Integration and MCP action ids pass through to connected tools. Free cannot run any of this. Starter gets three automations. Pro and Business are unlimited.

Automations edit on a canvas

The automations list is the index — On or Off, last run, the trigger label, the action chain. The editor is a canvas. It is the same graph editor a chat flow uses: a trigger node, then action nodes you connect in order. Save needs a name, a trigger, and at least one action wired to that trigger. An action sitting on the canvas with no edge is not saved. The builder tells you to connect it.

You pick the trigger and each action from a searchable catalog. Native ids stay the ones above. Integration and MCP tools show up as catalog rows once the connection is live. The rail can still write the same object with create_automation. If the graph is wrong, you open /automations/{id}/edit and move the nodes. Test run writes a history row on that automation — last fifty, same cap as a flow run — success or failed, step by step.

A live flow records a run

Attach a chat flow to a widget. The graph runs only while the flow is live. A visitor message can produce bot replies as the widget name, a handoff that sets inbox status to pending, and a flow run stored on the flow and published as an inbox event on that conversation. Draft and paused flows do not answer the public widget.

The runner walks trigger, message, condition, action, handoff, and delay nodes. Message text can interpolate values from the run context. A handoff stops the graph and marks the conversation pending so a person picks it up in the same inbox. Failed steps stay on the run. The flow builder lists the last fifty runs — success or failed, step by step. Recent runs on that canvas also link to /logs.

The builder agent in the rail still drafts the flow. Live is a save state on the same object. You can open the manual flow builder and move nodes if the draft is wrong. The public widget does not care who last edited the graph. It cares whether the flow is live.

/logs is both run kinds

The flow builder still lists the last fifty runs on that flow. The automation builder lists recent runs on that automation. /logs is the workspace table that merges them: every flow run and every automation history row, newest first. Tabs are All, Flows, or Automations. Search hits the name, the trigger, the error, and the step labels.

A row expands to the same step list the builder shows. Open flow or Open automation jumps to the canvas that produced it. The Flows and Automations pages both put Logs in the header. Search should not index /logs. It is a signed-in workspace route. This guide is the public sentence.

The widget is how the visitor starts

A visitor does not open your workspace. They hit a floating launcher, a support page iframe, or a pane inside your product. The first message opens a widget-channel conversation keyed by widget id and visitor id. From there it is an inbox thread: assign, snooze, resolve, attach a live flow, run an automation.

The live frame at /widget/{id} is noindexed. Search should find this guide, not the chat iframe. Install copies a snippet from the workspace. Free workspaces show the Heliune mark on the widget; paid plans do not.

The builder stays in the rail

Routing used to mean leaving the queue. Heliune keeps the builder agent in the rail: describe a refund flow or a widget, get a workspace object, then open the manual editor if the draft is wrong. Tool calls include create_chat_flow, create_widget, update_widget, create_automation, create_dashboard, and list_workspace.

list_workspace is how the rail sees what already exists. It should not invent a second flow when one is already attached to the widget. The rail is not a second inbox. The conversation you are looking at stays on the left.

What this is not

It is not a standalone phone app that emails you a recording. It is not a help-center search box with a chat overlay that never opens a ticket. It is not ChatGPT in another tab. If the visitor started in the widget, the supervisor whispered on the room, and the note was resolved in the same inbox, you used the product as it is built.

A day in the same objects

Morning: a widget visitor hits a starter chip. The first message opens an inbox conversation. A live flow greets them as the widget and hands off pending. An automation on conversation.created tags the thread. Someone in the queue replies from the same row.

Midday: the visitor asks to talk. The workspace opens a LiveKit room. A supervisor joins on listen, then whispers. Nobody stands up. The note after the room closes is still that conversation. Afternoon: resolve. conversation.resolved opens a follow-up task. /logs shows that automation row next to the morning flow run. The rail drafts a tighter flow for the next visitor. You open the builder and fix one node before you set it live.

None of those steps required a second login. That is the bar for this page. If a sentence on a vendor site cannot name the inbox row, the room, or the flow run, it is not describing this workspace.

What each plan actually includes

Free is two seats, one widget, one flow, twenty-five builder messages, and no voice minutes. The launcher shows the Heliune mark. You can still resolve and snooze. You cannot run automations or join a supervisor room.

Starter is four seats, three widgets, three flows, three automations, and a hundred builder messages. Voice minutes stay at zero. Integrations that exist on Starter are Slack, webhook, Discord, and Twilio. The mark drops.

Pro is eight seats with extra seats allowed, unlimited widgets, flows, and automations, four hundred builder messages, and fifty voice minutes. Custom MCP and custom dashboards turn on. Business raises seats to fifteen, builder messages to twelve hundred, and voice minutes to two hundred. Extra voice packs are three hundred minutes. Extra builder packs are five hundred messages. Those packs do not invent a second product.

If a vendor page says “omnichannel” and then hides the seat, minute, and automation counts, it is selling a feeling. This workspace sells the objects. Pick the plan that has the object you need. Do not buy Pro because a landing page said voice is the future.

What still fails if you split the stack

Paste the widget thread into a phone product and the supervisor who listens has no inbox row. Paste the recording into the ticket later and conversation.resolved already fired without the room. Run the bot in another tab and the flow run never lands on the conversation the person is reading.

Those are the failure modes this shell is built to avoid. The visitor id, the widget id, the conversation id, the flow run, and the LiveKit room are meant to point at one another. When they do not, you are not using the product — you are using a pile of exports.

Search should keep finding this note. The live frame, the inbox, /logs, and /api stay noindexed. A stranger comparing vendors should finish this page knowing which object they will open on day one: the inbox row, the room, the live graph, the automation canvas, or the rail that drafts the next one.

Four channels, one list

The inbox row carries a channel: chat, voice, email, or widget. The empty state says those four by name. A widget visitor and a later LiveKit room are still one conversation if the workspace kept them that way. Email is a channel on the same list, not a mailbox product you reconcile at the end of the week.

Search filters the list by customer name, subject, or last message. It does not hide resolved threads if you are on the Resolved tab. It does not invent a second queue. inbox.write is what lets someone reply, snooze, or resolve. Viewers can read. They cannot clear the thread.

If your current stack has a chat inbox, an email inbox, and a phone inbox, this page is the argument for one list. Not because “omnichannel” sounds finished. Because resolve, unread, and conversation.resolved only make sense when those channels share an object.

More guides