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://timisha-solutions-api.salamu.co.ke/api/v1/ussd/extensions" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Request an extension

POST/api/v1/ussd/extensions
Parameters
ussd_code_idreq
string

UUID of the shared USSD code

extensionreq
string

Extension string (e.g. 42)

networksreq
string[]

Networks to activate on

quoted_price
number

Quoted monthly price if known

curl -X POST "https://timisha-solutions-api.salamu.co.ke/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
mode
string

menu | callback | survey

callback_url
string

Webhook URL for callback mode

survey_id
string

Survey UUID for survey mode

menu_id
string

Menu UUID for menu mode

curl -X PUT "https://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/api/v1/ussd/extensions/ext-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Menus

List menus

GET/api/v1/ussd/menus
curl -X GET "https://timisha-solutions-api.salamu.co.ke/api/v1/ussd/menus" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Create a menu

POST/api/v1/ussd/menus
Parameters
namereq
string

Menu name (internal)

header_textreq
string

Text shown at the top of every menu screen

invalid_input_textreq
string

Message shown when a subscriber enters an invalid option

description
string

Internal description

curl -X POST "https://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/api/v1/ussd/menus/menu-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
PUT/api/v1/ussd/menus/{uuid}
curl -X PUT "https://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/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_numberreq
string

Number the subscriber types (e.g. 1, 2, 0 for back)

labelreq
string

Display label in the parent menu list

typereq
string

menu | end | callback, what this node does

display_text
string

Text shown when this node is active (for end/callback types)

callback_url
string

URL to POST to for callback-type nodes

parent_id
string

Parent node UUID. Omit for the root node.

sort_order
integer

Display order within the parent

Create the root node (first screen):

curl -X POST "https://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/api/v1/ussd/menus/nodes/node-uuid" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
PUT/api/v1/ussd/menus/nodes/{uuid}
curl -X PUT "https://timisha-solutions-api.salamu.co.ke/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://timisha-solutions-api.salamu.co.ke/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.