Guide · Flow agents
Build your first flow agent
A flow agent follows a path you draw: fixed questions, buttons and replies you've written and approved. This guide builds a small one from scratch, twice: once by dragging boxes on the canvas, and once by pasting JSON.
- Plan Pro and above
- Time about 15 minutes
- Code none needed
1What you're building
A deterministic agent never lets an AI model write a reply or decide what happens next. Every message it sends is text you wrote, and every turn follows a link you drew. That makes it the right choice for payments, claims, bookings, forms and anything else that has to follow an approved script. By default, incoming messages go through the same safety check as every Flexaura agent (OpenAI’s moderation service). On the Team plan you can switch that to a word list on Flexaura’s servers, or off, under AI usage on the flow page, so the agent sends nothing to any AI provider.
The example is a small business helper. It greets the visitor with three buttons, answers “Opening hours”, books a callback by asking for a phone number and confirming it, and hands the visitor to your team when they ask for a person.
The finished flow. Dashed boxes are where a conversation can start; grey, slanted links are the paths taken when something goes wrong.
Four words you’ll see everywhere
Step
One box on the canvas: a message, a question, a check, an API call, a handoff. Each step has a name, like menu.
Link
An arrow from one step to the next. A Buttons step has one link per button, plus No match for anything else.
Start badge
Where a conversation can enter the flow: an intent (keywords that start a task), the fallback (“Anything else”), or a keyword command that works anywhere.
Variable
Something the flow remembered, like the phone number a visitor typed. Use it in any text as {{ phone }}.
2Create the agent
- In the dashboard, click + New agent. A window asks what kind of agent to build.
- Choose Deterministic (“No AI-written replies”), then Create deterministic agent. On the Free plan this card shows an upgrade link instead, because flow agents are on Pro and above. (Hybrid is a flow agent with AI behind it for everything the flow doesn’t cover; it has its own guide.)
A short wizard opens, with three steps:
- Basics. Agent name is what you’ll see in your dashboard, for example Front desk. Persona name (optional) is the name visitors see at the top of the chat, for example Acme Studio. Description (optional) is a note for your team. Under Avatar, upload an image (PNG, JPEG, WebP or GIF, up to 5 MB) or pick a colour.
- Look. The chat’s Colour, its Position (bottom right or bottom left) and the Welcome message shown when the chat opens.
- Create. A preview of the chat’s header and welcome message, as visitors will see them, and Start from: a ready-made flow template, or Blank.
Click Next to move on, or Back to change something.
- Under Start from, pick Blank. The wizard picks Callback request for you, but in this guide you build the flow yourself, so you need an empty canvas.
- Click Create and build the flow. You land on the agent’s flow page, with an empty canvas.
No harm done: nothing is live. Either keep it (the Callback request template is close to the flow this guide builds, so you can follow along by reading its boxes), or create another agent with Blank and remove this one from the Agents list.
Everything from the wizard can be changed on the flow page, in the Details and appearance section.
3Find your way around the flow page
Everything about a flow agent lives on this one page. From top to bottom:
| Part | What it's for |
|---|---|
| Canvas JSON (advanced) | Two views of the same flow. Change it in one and the other updates straight away, so you can switch at any time without losing anything. |
| + Add step Tidy up | Add a box, an intent, a keyword command or a sub-flow. Tidy up lays the boxes out again neatly. |
| Inspector | The panel that opens on the right when you click a box. It holds the box's name, its text and settings, where each link goes, and a delete button. |
| Full screen | Spreads the editor over the whole window, hiding the side menu and top bar, so the canvas gets every bit of room. Everything works the same there, including Test. Press Esc or the same button to go back; nothing is lost either way. |
| Test Save draft Publish | Your work is a draft until you publish it. Visitors only ever see the published (live) version. |
| Tests | Opens your saved tests under the canvas: scripted conversations that check the flow still does what it should. Run them any time; publishing runs them too. See Save it as a test. |
| Changes | Appears once something is live. Marks every box that’s New or Changed compared with the live version, including edits you haven’t saved, and lists them (removed steps too) under the canvas. Click an entry to jump to its box. |
| Issues list | Under the canvas. It lists anything that would stop the flow from publishing, and the box it belongs to gets a red badge. |
| Sections below | Secrets (API keys for your own systems), Handoff email, Verified visitors, AI usage (which AI providers see the conversations, and how incoming messages are checked), Details and appearance (name, avatar and the chat’s look), Versions (every published version, who published it and why; open one to compare or restore it) and Put it on your website. |
The canvas needs a wide screen. On a phone the page shows the JSON view instead.
4Build the flow
Pick the way that suits you. Both build exactly the same flow, and you can mix them: build on the canvas, then peek at the JSON, or paste JSON and fine-tune it on the canvas.
Part A: a menu, an answer and a handoff
The empty canvas already shows one start badge, Anything else, marked “No step set”. That’s the fallback: where every conversation goes when nothing else matches. You’ll point it at your menu.
- Click + Add step and choose Buttons. A box appears in the middle and the inspector opens.
- In the inspector, change Step name to
menuand press Enter. Type the Question: Hi! What can I help you with? - Under Buttons, rename Option 1 to Opening hours. Click Add button and call the new one Talk to a person.
- Add a End step. Name it
hoursand set its Last message to We’re open 9am to 5pm, Monday to Friday. - Add a Hand off step. Name it
to_human. Its Message is what the visitor is told as the chat passes to your team; it starts as I’m passing you to our team. Someone will reply here shortly. Its Reason is shown to your team in Conversations, not to the visitor. Connect the boxes. On the
menubox, each button has a small dot on its right edge. Drag from the dot next to Opening hours onto thehoursbox. Drag Talk to a person and No match ontoto_human.Prefer not to drag? Every link is also a drop-down list under Links in the inspector.
- Click the Anything else badge and set its Step to
menu. - Choose + Add step → Intent. In the inspector set Intent name to
opening_hours, the Button label to Opening hours, Keywords to hours, open, and First step tohours. Now a visitor who types “are you open?” skips the menu and gets the answer. - Choose + Add step → Keyword command. Replace the keywords with agent, human and set Go to to
to_human. A keyword command works anywhere, even in the middle of a question. - Click Save draft (or press ⌘ S / Ctrl S). The issues list should say No issues. This draft can be published.
Part B: book a callback
Now teach it to ask a question, check the answer and confirm it.
Add an Ask for step and name it
ask_phone. Set the Question to Sure. Which number should we call?, Save the answer as tophone, and What it accepts to A phone number. Tick Ask even if it’s already answered, so the visitor can correct a wrong number.The flow checks the answer for you: “123” isn’t a phone number, so it asks again, and after too many tries it follows Gave up.
- Add a Confirm step named
confirm_call. In its Question, type We’ll call you on, click the { } button beside the box and pickphone, then finish with . Is that right? - Add an End step named
call_booked, with the message Thanks! We’ll call you within one working day. Tick Mark the conversation resolved. Link them up:
ask_phone: Got it →confirm_call, Gave up →to_humanconfirm_call: Yes →call_booked, No →ask_phone, No answer →to_human
- Click
menu, add a button called Request a callback, and link it toask_phone. Button order is up to you. - Optionally add a second intent,
callback, with the keywords callback, call me and the first stepask_phone. - Click Tidy up if the boxes are crowded, then save.
A booked callback is only useful if someone hears about it. Add a Notify by email step between confirm_call’s Yes and call_booked, send it to your own address, and set the Subject to Callback request: followed by phone from the { } picker. Add a Mark goal step called callback_booked too, so your reports can count them.
Undo and redo are the arrow buttons beside the view switch, or ⌘ Z and ⌘ Shift Z (Ctrl on Windows). Undo goes back as far as when you opened the page. To remove a box or an arrow, click it and press Delete.
The JSON view is the same flow written as text. It suits people who’d rather type than drag, teams that review changes as text, and copying a flow from one agent to another.
- Click JSON (advanced) above the canvas.
- Paste the flow below into the box, replacing whatever is there. The page checks it a moment after you stop typing and lists any issues underneath.
- Click Canvas to see it drawn as boxes. It’s the same flow the canvas steps build.
- Click Save draft.
{
"version": 1,
"intents": {
"opening_hours": {
"label": "Opening hours",
"keywords": ["hours", "open"],
"entry": "hours"
},
"callback": {
"label": "Request a callback",
"keywords": ["callback", "call me"],
"entry": "ask_phone"
}
},
"fallback": "menu",
"global_commands": [
{ "keywords": ["agent", "human"], "goto": "to_human" }
],
"nodes": {
"menu": {
"type": "choice",
"prompt": "Hi! What can I help you with?",
"options": [
{ "label": "Opening hours", "next": "hours" },
{ "label": "Request a callback", "next": "ask_phone" },
{ "label": "Talk to a person", "next": "to_human" }
],
"on_fail": "to_human"
},
"hours": {
"type": "end",
"message": "We're open 9am to 5pm, Monday to Friday."
},
"ask_phone": {
"type": "collect",
"slot": "phone",
"prompt": "Sure. Which number should we call?",
"entity": { "kind": "phone" },
"ask_again": true,
"next": "confirm_call",
"on_fail": "to_human"
},
"confirm_call": {
"type": "confirm",
"prompt": "We'll call you on {{ phone }}. Is that right?",
"yes": "call_booked",
"no": "ask_phone",
"on_fail": "to_human"
},
"call_booked": {
"type": "end",
"message": "Thanks! We'll call you within one working day.",
"resolve": true
},
"to_human": {
"type": "handoff",
"message": "I'm passing you to our team. Someone will reply here shortly.",
"reason": "Visitor asked for a person"
}
}
}How to read it
| Key | On the canvas | What it holds |
|---|---|---|
intents | Intent badges | Each task a visitor can ask for: its label, the keywords that start it, and the entry step it starts at. |
fallback | Anything else | The step for messages that match nothing, usually your menu. |
global_commands | Keyword command badges | Keywords that work anywhere, and the step they jump to (goto). |
nodes | The boxes | Every step, keyed by its name. type says what kind of step it is. |
next, yes, no, on_fail… | The arrows | A link is just the name of the step it goes to. Rename a step in JSON and you must update its links by hand; on the canvas, renaming does that for you. |
{{ phone }} | The { } picker | A variable saved earlier in the flow, here by "slot": "phone". |
- JSON is strict: every key and text value needs double quotes, and there’s no comma after the last item in a list. If the text can’t be read, the canvas shows a message instead of the diagram until you fix it.
- An edit made on the canvas rewrites the JSON in a standard layout, so your own spacing isn’t kept.
- Box positions aren’t part of the JSON: they’re stored separately, so copying or pasting a flow never carries them along. A pasted flow is laid out automatically.
5Save, fix the issues, publish
Save draft keeps your work without changing what visitors see. Publish makes the saved draft the new live version. It stays greyed out until the draft is saved and has no issues.
Publish asks one thing first: What changed? The note is optional. A few words like “Added a returns menu” show up in the version history, so your team (and you, next month) knows why each version exists. The dialog also says how many changes are about to go live; to see them, close it and press Changes.
Flexaura checks the whole flow while you work. Click an issue’s location (like nodes.menu.on_fail) to jump to its box. The ones beginners meet most:
| You see | It means | Fix |
|---|---|---|
| A link marked not set, or “Field required” | A link that has to go somewhere doesn't yet. | Drag its dot to a box, or pick a step under Links. |
| "There's no node called 'x'." | A link points at a step name that doesn't exist, often after a typo or a rename in JSON. | Point the link at the right step. |
| "Nothing leads to this node." | No start badge or link reaches this box, so it could never run. | Link to it, or delete it. |
| "'phone' isn't set anywhere in this flow." | A {{ variable }} that no step saves. | Check the spelling, or save it with an Ask for step. |
| "Two buttons have the same label." | Visitors couldn't tell which one they pressed. | Give each button a different label. |
| "There's no secret called 'x'." | An API call uses a secret you haven't added. | Add it under Secrets, lower on the page. |
Going back to an earlier version
Every publish is kept. Under Versions, lower on the page, each version shows when it was published, who published it and their note.
- Click Open on a version. The Changes tab lists what’s different from the version before it: steps that are new, removed or changed, and which part of each step changed (“Reply text, Then”). Pick another version under Compared with, or switch to JSON to read the whole thing.
- To bring it back, click Restore to draft, then Replace the draft. The page scrolls up to the editor, which now shows that version.
- Check it, then Publish. The note starts as “Restored version 1”; keep it or say why.
It only replaces the draft. Publishing it makes a new version (version 4, say, with version 1’s content), so the history is never rewritten, and the usual checks run: if the old version uses a secret you’ve since deleted, it shows as an issue to fix first. If you have unsaved edits in the editor, Restore waits until you save or undo them.
6Test it
- Publish first. Tests always talk to the live version, exactly as a visitor would.
- Click Test. A chat opens on the right of the page.
- Say hi, press the buttons, type a wrong number such as “123”, then answer No to the confirmation. Type agent at any point to try the keyword command.
- After agent (or Talk to a person), the agent sends the handoff message and then stays quiet: the conversation now belongs to your team, exactly as it would for a real visitor. In Conversations you’ll see a line saying it was handed to your team, with the reason. Click Return to bot there to carry on testing, or clear the test chat to start again.
- Watch the canvas while you chat: the boxes and arrows each reply went through turn green, darkest for the latest reply.
Save and publish again. A conversation keeps the version it started on, so publishing starts a fresh test conversation for you. If the test drawer warns that your latest changes aren’t live yet, that’s why.
A handoff puts the conversation in Conversations, where your team can take over. Set an address under Handoff email to get an email each time it happens.
Save it as a test
Chatting by hand after every change gets old fast. A saved test replays a conversation for you in about a second and checks the flow still does what it did: like a recorded test drive you can rerun after every change.
- Chat through the callback path in the Test drawer, then click Save as test at the top of the drawer.
- A form opens, already filled in from that chat: each message you sent, the step it stopped at, the first sentence of each reply, and any handoff or goal. Give it a name such as Callback, happy path, delete any check you don’t care about, and click Save test.
- Click Tests on the editor and Run all. A green tick means it passed.
- Now change the callback confirmation’s text a little, without saving, and run it again. It fails, says which message and why (“The reply doesn’t contain …”), and Path lights up the steps it took on the canvas. Undo the change, and it passes again.
| Check | Passes when |
|---|---|
| Reaches steps | The message goes through every step listed (by name, like ask_phone). |
| Reply contains | The reply includes each line, ignoring capitals. |
| Hands off to your team | Yes: the message ends with a handoff. No: it doesn't. |
| More checks | Never reaches a step, a reply that must not say something, the exact buttons offered, a goal marked, emails a Notify by email step would send, and whether the conversation is marked resolved. |
They run on your draft (unsaved changes included), not the live version, and never call your APIs or send email. Each API call step needs a test answer instead: the status and response body it should get back. A step without one fails the test with “has no test answer”. Use Test as a verified visitor in the form for flows behind a Verified only step, and Pretend it’s for flows that check the date.
Publishing runs every saved test first. By default a failing test only warns you after publishing. Tick Publishing needs every test to pass in the Tests panel and a failing test stops the publish instead, listed with the issues. An agent can have up to 50 tests.
7Put it on your website
- Check the name, avatar and look under Details and appearance. You set them when you created the agent; change them here if you need to, and click Save details.
- Under Put it on your website, click Go live. It’s available once the flow has been published at least once.
- Copy the embed code you prefer (the JavaScript snippet, the React component or the iframe) into your site.
The iframe picks up changes to Details and appearance by itself. The JavaScript and React snippets include the look and the avatar, so copy them again after you change them. Flow changes need no new code: publishing is enough.
8Improve it from real conversations
However carefully you choose keywords, visitors will say things you didn’t think of: “my parcel never turned up” instead of “where is my order”. A flow agent can’t guess, so those messages get the fallback (your menu). Analytics shows you exactly which ones, and lets you teach the flow in two clicks.
- Open the agent’s menu in the Agents list and choose Analytics. Scroll to the Flow section.
- How messages were understood counts how messages started a task: by a button, a keyword, a synonym, a typo, their meaning, and how many weren’t understood at all. Over time you want the last number shrinking.
- Not understood lists those messages, most common first. View opens the conversation, so you can see what the visitor was after.
Click + Add to an intent next to a message, pick the intent it meant, and choose how to add it:
- An example phrase: messages that mean the same thing start the intent, even in other words. This needs Match messages to intents by meaning switched on under AI usage on the flow page (it uses OpenAI, so it isn’t available when the agent sends nothing to AI providers).
- A keyword: any message containing those exact words starts the intent. Best for short phrases, and works without any AI.
The dialog recommends one, based on your AI usage setting.
- Click Add to draft. The message now shows In “Request a callback” instead of the button.
- Open the flow page and Publish. Additions go into your draft, never straight to visitors, so you can review them (the Changes switch marks the intent as changed) and publish several at once.
If the flow page is already open in another tab, reload it before you save there. Otherwise saving that tab’s older draft would undo what you just added.
Under Understanding on the canvas, typo tolerance is on by default (“frezee” still finds “Freeze a card”, with a “Did you mean…” to check), and you can add synonyms (“mc” for “Mastercard”) that work in every keyword and button at once.
9Step types at a glance
All 16 are in + Add step. (Hybrid agents get a 17th, AI answer, which a deterministic agent can’t use.) “Waits” means the step stops and waits for the visitor’s next message. The Flow step handbook explains each one in full.
| On the canvas | In JSON | What it does | Waits |
|---|---|---|---|
| Message | message | Sends your text and moves on. | No |
| Buttons | choice | Asks a question with up to 6 buttons; each button is a link. Typed keywords can pick a button too. | Yes |
| Ask for | collect | Asks for one answer and checks it: text, number, amount, email, phone, date, yes/no, a list, or a pattern. | Yes |
| Confirm | confirm | Reads details back and needs a clear yes. Put one before anything that changes data. | Yes |
| Condition | condition | Branches on rules like "balance is less than 100". | No |
| Switch | switch | Branches on one variable's value, with a case per value. | No |
| Set variables | set_variable | Saves or clears variables. | No |
| API call | http | Calls your own system (HTTPS only), saves fields from the reply, and has an Error link. | No |
| Verified only | require_identity | Continues only when your website has told Flexaura who the visitor is. | No |
| Sub-flow | run_subflow | Runs a reusable piece of flow (its own tab) and comes back. | Maybe |
| Once | once | One path the first time, another every time after, for a welcome shown once. | No |
| Go to | goto | Jumps to another step or intent without coming back. | No |
| Hand off | handoff | Sends an optional message, then passes the visitor to your team in Conversations. | No |
| Notify by email | notify_email | Emails up to 5 fixed addresses on your team (a callback request, a new claim) and moves on. At most 3 per conversation. | No |
| Mark goal | mark_goal | Records an outcome such as "callback booked" for your reports. Visitors don't see it. | No |
| End | end | Sends an optional last message and ends the flow; can mark the conversation resolved. | No |
10Shortcuts and tips
| Do this | How |
|---|---|
| Save the draft | ⌘ S or Ctrl S |
| Undo / redo a canvas edit | ⌘ Z / ⌘ Shift Z (Ctrl on Windows) |
| Delete a box or an arrow | Click it, then Delete or Backspace |
| Insert a variable into text | The { } button beside a text box |
| Find a problem | Click its location in the issues list |
| More room for the canvas | Full screen; Esc to leave |
| Rearrange the canvas | Drag boxes anywhere, or Tidy up. Positions save by themselves and never change what the flow does. |
- Start from a template. Six ready-made flows (Callback request, Appointment request, Order status, Returns and refunds, Lead qualification, Freeze a card), each with its own saved tests. Pick one on the Templates page or in the wizard, or use Start from a template on an empty flow (or Start over from a template under the canvas). It replaces the draft, never what’s live. Templates use stand-ins like
team@example.comand name any secret they need, and the issues list keeps the flow from publishing until you’ve replaced them with your own. - Give every question a way out. Link No match, Gave up and No answer to a handoff or the menu, so a visitor is never stuck.
- Name steps by what they do.
ask_phoneis easier to follow later thanask_for_3. - Leaving with unsaved changes makes the browser ask first.