{ nodes, edges } graph, run the same validator, and publish the same live snapshot. This walkthrough puts the two side by side so you can pick the right surface per change — and switch mid-flight without re-authoring, since both read and write the same flow.
1. The Flow DSL
The DSL is a JSON graph you submit toPOST /api/v1/voice/ivr-flows and update with PUT /api/v1/voice/ivr-flows/:id. Each entry in nodes carries an id, a type (ivrStart, playAudio, menu, speechInput, queue, transfer, voicemail, hangup), and an optional data block; each edge in edges links a source to a target, with a sourceHandle naming the branch ("1", "default", an intent name).
Definition
422 IVR_FLOW_GRAPH_INVALID and stores nothing. The full node catalog, per-type data payloads, and validator codes are in Build and ship your first IVR flow — this page does not repeat them.
2. Visual canvas mode
Open Voice → IVR Builder. Drag a node from the left palette onto the canvas (or click the palette entry to drop it at the current insert point), drag edges from a source handle to a target node, and click any node to edit itsdata block in the right-hand config panel. A Menu node exposes one handle per option key plus default; a Speech Input node exposes one per intent plus nomatch.
Save stays a draft until you publish — nothing a caller can reach. Publish promotes the draft to the live snapshot, and Assign to Number from the toolbar (or the number’s Routing tab) attaches the flow to a DID. Design IVR flows on the visual builder is the full canvas reference.
Side by side, the same two-node branch:
The canvas never stores a different shape: what you see is serialized to the same graph and sent to the same endpoints.
3. When to choose the canvas vs the DSL
Both surfaces are tenant-owned authoring choices — pick per change, not per team.- Choose the canvas when routing reads better as a diagram: a multi-level menu, a branch a teammate should review at a glance, the speech-grammar editor for a Speech Input node, or per-node funnel analytics that tell you what to fix next. It is also the only place with a guided validator panel, an in-product simulator, and one-click rollback.
- Choose the DSL when the definition belongs in a repo: flows reviewed in pull requests, templates rendered across many tenants or brands, a CI gate that PUTs a candidate and treats
422as a failed check, or an infrastructure-as-code pipeline that ships IVR alongside the rest of your config.
4. Editor behaviors on the canvas
Small behaviors that change how you work:- Snap-to-tree. Dropped nodes land at the current insert point and Auto-layout re-sorts the tree into a readable vertical flow; Fit view re-frames a long canvas. You arrange for a review, the layout button restores the tree.
- Hover hints. Palette entries carry a one-line description (
Entry point,Collect digits,Press 1, 2, 3...); toolbar buttons show tooltips for Validate, Auto-layout, Fit view, History, and the unsaved-changes indicator. - Validator feedback. Validate (and every publish) lists each issue in a panel — “Fix each highlighted node before publishing.” Click an issue and the canvas focuses the offending node. A second Start node is refused outright; disconnected nodes, dead-end branches, and cycles are flagged, and backend-confirmed loops highlight the cycle edges in red. Dismiss the panel and the same issue set stays dismissed — a different validator response re-opens it.
- Selection safety. Delete/Backspace removes the selected node, but the keys are suspended while autosave is in an error state so a failed save never costs you a node.
5. Simulate a call before you publish
Before attaching a DID, step a scripted caller through the draft with Simulate in the toolbar (orPOST /api/v1/voice/ivr-flows/:id/simulate). Add turns — digits, speech, or an intent — and the walk reports the node reached at each step, the handle it took, the verb categories emitted, and the termination reason. Interactive nodes pause for input; digit buffers at a DTMF input node resolve per your maxDigits / terminator settings.
Run three walks per change: the happy path, an unmatched option (falls through default), and the silent caller (no input). The canvas dialog and the API consume the same graph — canvas operators and CI pipelines test the identical routing before it can ring a phone.
6. Version history and rollback
Every publish appends a version. Open History in the toolbar to list each published snapshot with its publish time and node count, preview a snapshot’s nodes, and confirm a revert. A revert is a publish: the prior snapshot becomes the new head and the new draft in one action, and the attached DID keeps answering on the reverted definition — no manual re-edit, no re-attach. The equivalent API path (GET /api/v1/voice/ivr-flows/:id/versions, POST .../versions/:version/revert) is covered in the DSL guide.
See also
- Build and ship your first IVR flow — the full DSL/API contract side.
- Design IVR flows on the visual builder — the canvas reference page.
- IVR intents — speech menus and per-tenant intent buckets.