Menus & Nodes

Build the interactive screens subscribers step through, and take extensions off shared codes.

A menu is a named tree of screens. Each node is one screen with a prompt and a set of child options. Menus attach to a USSD code or an extension through the menu_id field. An extension is a sub-code under a shared code, e.g. *657*42# where 42 is your extension on the shared *657#.

Extensions

Extensions can be routed to a menu, a survey, or a custom callback URL, just like a dedicated code.

List extensions

GET/api/v1/ussd/extensions
curl -X GET "https://smsapi.zuriontech.com/api/v1/ussd/extensions" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Request an extension

POST/api/v1/ussd/extensions

Parameters

ussd_code_idstringrequired
UUID of the shared USSD code
extensionstringrequired
Extension string (e.g. 42)
networksstring[]required
Networks to activate on
quoted_pricenumber
Quoted monthly price if known
curl -X POST "https://smsapi.zuriontech.com/api/v1/ussd/extensions" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "ussd_code_id": "code-uuid",
  "extension": "42",
  "networks": [
    "safaricom"
  ]
}'

Update an extension

PUT/api/v1/ussd/extensions/{uuid}

Parameters

modestring
menu | callback | survey
callback_urlstring
Webhook URL for callback mode
survey_idstring
Survey UUID for survey mode
menu_idstring
Menu UUID for menu mode
curl -X PUT "https://smsapi.zuriontech.com/api/v1/ussd/extensions/ext-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "menu",
  "menu_id": "menu-uuid"
}'

Delete an extension

DELETE/api/v1/ussd/extensions/{uuid}
curl -X DELETE "https://smsapi.zuriontech.com/api/v1/ussd/extensions/ext-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Menus

List menus

GET/api/v1/ussd/menus
curl -X GET "https://smsapi.zuriontech.com/api/v1/ussd/menus" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Create a menu

POST/api/v1/ussd/menus

Parameters

namestringrequired
Menu name (internal)
header_textstringrequired
Text shown at the top of every menu screen
invalid_input_textstringrequired
Message shown when a subscriber enters an invalid option
descriptionstring
Internal description
curl -X POST "https://smsapi.zuriontech.com/api/v1/ussd/menus" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Main Menu",
  "header_text": "Acme Services",
  "invalid_input_text": "Invalid choice. Please enter a number from the menu."
}'

Get, update, delete a menu

GET/api/v1/ussd/menus/{uuid}
curl -X GET "https://smsapi.zuriontech.com/api/v1/ussd/menus/menu-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
PUT/api/v1/ussd/menus/{uuid}
curl -X PUT "https://smsapi.zuriontech.com/api/v1/ussd/menus/menu-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Main Menu",
  "header_text": "Acme Services (Updated)"
}'
DELETE/api/v1/ussd/menus/{uuid}
curl -X DELETE "https://smsapi.zuriontech.com/api/v1/ussd/menus/menu-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Nodes

Nodes form the tree structure. A node with no parent_id is the root, the first screen a subscriber sees. Each node has an option_number the subscriber types to reach it, and a type controlling what happens next.

Create a node

POST/api/v1/ussd/menus/{uuid}/nodes

Parameters

option_numberstringrequired
Number the subscriber types (e.g. 1, 2, 0 for back)
labelstringrequired
Display label in the parent menu list
typestringrequired
menu | end | callback, what this node does
display_textstring
Text shown when this node is active (for end/callback types)
callback_urlstring
URL to POST to for callback-type nodes
parent_idstring
Parent node UUID. Omit for the root node.
sort_orderinteger
Display order within the parent

Create the root node (first screen):

curl -X POST "https://smsapi.zuriontech.com/api/v1/ussd/menus/menu-uuid/nodes" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "option_number": "0",
  "label": "Main Menu",
  "type": "menu",
  "sort_order": 0
}'

Create a child option under the root that hands off to your server:

curl -X POST "https://smsapi.zuriontech.com/api/v1/ussd/menus/menu-uuid/nodes" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "parent_id": "root-node-uuid",
  "option_number": "1",
  "label": "Check balance",
  "type": "callback",
  "callback_url": "https://yourserver.com/ussd/balance",
  "sort_order": 1
}'

Get, update, delete a node

Node operations are keyed by node UUID, not the parent menu.

GET/api/v1/ussd/menus/nodes/{uuid}
curl -X GET "https://smsapi.zuriontech.com/api/v1/ussd/menus/nodes/node-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
PUT/api/v1/ussd/menus/nodes/{uuid}
curl -X PUT "https://smsapi.zuriontech.com/api/v1/ussd/menus/nodes/node-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "label": "Check airtime balance",
  "sort_order": 1
}'
DELETE/api/v1/ussd/menus/nodes/{uuid}
curl -X DELETE "https://smsapi.zuriontech.com/api/v1/ussd/menus/nodes/node-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Test before you ship

Once a menu is attached to a code, dial it end to end with USSD simulation, no handset or carrier integration needed.