Skip to main content
One IVR flow, two doors in. The visual canvas in the dashboard (Voice → IVR Builder) and the Flow DSL over the API write the same { 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 to POST /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
Every create and update runs the graph validator before persistence; a malformed graph returns 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 its data 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 422 as a failed check, or an infrastructure-as-code pipeline that ships IVR alongside the rest of your config.
Teams mix both per flow over its lifetime. A support lead edits the holiday branch on the canvas; your pipeline re-renders the same flow from a template at deploy time. Because the graph is the contract either way, keep the DSL as the source of truth in version control and use the canvas for review and iteration — the visual-builder reference and the DSL guide cover the same flow lifecycle from each side.

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 (or POST /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