The USSD service enables you to build interactive menu-driven applications accessible via shortcodes (e.g., *123#). USSD sessions are stateful and support navigation through multiple menu levels.
User’s input (empty for first request, then contains menu selections)Examples:
"" - First request (main menu)
"1" - User selected option 1
"1*1" - User selected 1, then 1 (navigation path)
Implementation
# From routes/ussd.py:11-46@ussd_bp.route("/session", methods=["POST"])def ussd_handler(): # Read the variables sent via POST from our API session_id = request.values.get("sessionId", None) serviceCode = request.values.get("serviceCode", None) phone_number = request.values.get("phoneNumber", None) text = request.values.get("text", "") # Print the details print(f"session_id: {session_id}") print(f"serviceCode: {serviceCode}") if text == "": # First request. Start response with CON response = "CON What would you want to check \n" response += "1. My Account \n" response += "2. My phone number" elif text == "1": # First level response response = "CON Choose account information you want to view \n" response += "1. Account number" elif text == "2": # Terminal request response = "END Your phone number is " + str(phone_number) elif text == "1*1": # Second level response accountNumber = "ACC1001" response = "END Your account number is " + accountNumber else: response = "END Invalid choice" return response
@ussd_bp.route("/session", methods=["POST"])def ussd_handler(): text = request.values.get("text", "") phone_number = request.values.get("phoneNumber", None) if text == "": # Main menu response = "CON Welcome! Choose a service\n" response += "1. Check Balance\n" response += "2. Buy Airtime\n" response += "3. Help" elif text == "1": # Check balance balance = get_user_balance(phone_number) response = f"END Your balance is KES {balance}" elif text == "2": # Airtime amounts menu response = "CON Select amount\n" response += "1. KES 50\n" response += "2. KES 100\n" response += "3. KES 200" elif text == "2*1": # Buy KES 50 airtime send_airtime(phone_number, 50) response = "END KES 50 airtime sent to your number" elif text == "2*2": # Buy KES 100 airtime send_airtime(phone_number, 100) response = "END KES 100 airtime sent to your number" elif text == "2*3": # Buy KES 200 airtime send_airtime(phone_number, 200) response = "END KES 200 airtime sent to your number" elif text == "3": # Help response = "END For support, call 0711000111 or visit www.example.com" else: response = "END Invalid option. Please try again." return response
# From routes/ussd.py:49-78ussd_bp.route("/status", methods=["POST"])def ussd_status(): payload = {key: request.values.get(key) for key in request.values.keys()} print("📲 USSD Status Notification Received:") for key, value in payload.items(): print(f" {key}: {value}") # Always acknowledge with 200 OK return Response("OK", status=200)