Buni.aiDocs
USSD
USSD

Menus and sessions

How USSD menus route replies, navigate, list dynamic data and decide whether a session continues or ends.

Every screen a caller sees in a USSD project comes from a Menu node. This page explains how those screens behave at run time: which one opens a session, how a reply is matched, what the navigation keys do, and when the session ends. For every field on the node, see the Menu node reference.

Menu Type is the most consequential setting on the node. It decides whether the handset keeps the session open after showing the screen.

Menu TypeUse it forSession after the screen
MainThe first screen. Every new session starts here, and a flow must have exactly one.Stays open and waits for a reply.
IntermediaryEvery screen in the middle of a journey, including open prompts such as "Enter amount".Stays open and waits for a reply.
LastThe closing screen: a confirmation, a result, an error. It has no options or navigation.Ends. The handset shows the text and hangs up.

A Main or Intermediary menu with nothing connected after it also ends the session. The canvas warns about this ("Unintended Flow End") so that a screen does not end the call by accident; if it is meant to be the end, set it to Last.

How a reply is matched

In USSD the screen and the answer arrive in separate requests. Your flow shows a menu, the session pauses, and the caller's reply starts the next request. What happens next depends on how the menu is wired.

Options with their own destinations. In the structured editor, each option has a destination. The reply is compared with each option's key and the session moves to that option's node. A reply that matches no option shows the same menu again, and is recorded as an invalid input in the project's Activity tab.

A single output. A menu with no connected options (an open prompt, or a legacy menu) has one output handle. Whatever the caller types goes to the next node, which is usually a Router that inspects it.

The Output variable. If you set Output variable under Output, the caller's reply is stored in session state, so any later node can read it, for example {{state.accountType}}. When an option with a destination is chosen, the flow also sets {{state.selectedOption}} (the key) and {{state.selectedOptionLabel}} (the option's label).

Options

With Content Type set to Text, you write the options yourself under Menu Options:

  • Add Option adds a row. Keys are assigned in order (1, 2, 3...) and renumbered when you remove or drag a row.
  • Each option needs a label once any option is defined. Keys must be unique across options and navigation.
  • Option labels and the Menu Message can include variables, such as {{state.customerName}}.

The screen the caller receives is the message, a blank line, the options as 1. Label lines, and then the navigation lines. All of it counts towards the 160-character limit shown in the editor.

Under Navigation Options you can add up to three extra lines to a text menu. Each has a checkbox to turn it on, and a link button to connect it to a node.

OptionDefault keyWhat it does
Back0Goes to the node you connect it to. Left unconnected, it returns the caller to the Main menu.
More9Goes to the node you connect it to. Use it to split a long list over two screens: connect it to a second menu with the remaining options.
DefaultnoneSends any reply that matches no option or other navigation key to the node you connect it to, instead of re-showing the menu. It is shown on the screen as *. Label.

You can change the key and label of Back and More. Pick keys that do not clash with your options; the editor reports duplicates.

Dynamic lists

When the options come from data (accounts from an API, products from a data store) rather than from you, set Content Type to one of the dynamic types.

Content TypeThe previous node's output isAlso set
Dynamic string listA list of plain strings, such as ["Accra", "Kumasi"]Nothing
Dynamic object listA list of objectsDisplay Value: the key to show for each item, such as name

The list must be the output of the node directly before the menu, and the menu's message must include ${input} where the list should appear, for example Choose a branch: on one line and ${input} on the next. The canvas reports an error if it is missing.

At run time the list is numbered and shown four items per screen, followed by n: Next Page and p: Previous. The caller replies n or p to page, or a number to choose. The chosen item (the whole object, for an object list) is passed to the next node as its input.

How a session ends

Each response your project sends back tells the aggregator whether to keep the session open. You do not set this directly; it follows from the screen:

  • A Last menu, or any screen with nothing connected after it, ends the session.
  • Every other screen continues it.

How that is written on the wire depends on the USSD provider chosen for the project. For providers that use text responses, such as Africa's Talking, a continuing screen starts with CON and an ending one with END. Providers that use JSON get the equivalent field in their own format. Because the format is built into the published app, publish again after you change the provider in Settings.

If a step fails unexpectedly while the flow runs, the caller sees Something went wrong please try again later and the session ends.

Session state and timing

  • A session's state lives for that session only. When the caller dials again, they start a new session at the Main menu with empty state. To remember something between dials, store it in a data store or on the contact.
  • The caller's phone number is available as {{state.currentUserSessionSystemContext.phoneNumber}}, in the format your aggregator sends it.
  • The network sets the session time limit, and it is short. Avoid slow steps in the middle of a journey, and do not wait on anything the caller has to do elsewhere. For example, Collect Payment on USSD sends the payment request and moves straight on to your closing screen; the caller approves the payment after the session ends.

Keep menus usable

  • Put the most-used option first, and keep labels to a few words.
  • Aim for no more than six or seven options on a screen; use More for the rest.
  • Use the same Back key everywhere in a project.
  • End every branch on a Last menu that tells the caller what happened.
  • Avoid emoji and special symbols. Many handsets cannot show them, and the canvas warns about them.
Last reviewed 24 September 2026

On this page