Ussd extending the example to a Community-Based Surveillance (CBS) use case
Below is a technical walkthrough of the Africa’s Talking USSD flow, using your Flask / Express examples, and then extending the example to a Community-Based Surveillance (CBS) use case.
1. USSD Session Lifecycle (Africa’s Talking)
When a user dials your USSD code (e.g. *384*123#):
MNO receives the request
Request is forwarded to Africa’s Talking
Africa’s Talking sends an HTTP POST request to your
/ussdendpointYour application responds with:
CON→ session continuesEND→ session terminates
Africa’s Talking does not store session state. Your application is responsible for interpreting the
textfield.
2. Incoming API Payload (What Your Server Receives)
Content-Type:
application/x-www-form-urlencodedPayload fields:
| Field | Description |
|---|---|
sessionId | Unique identifier for the USSD session |
phoneNumber | MSISDN of the user |
networkCode | Mobile network (e.g. Safaricom, Airtel) |
serviceCode | Your assigned USSD short code |
text | User input, *-concatenated |
Example text evolution
| User Action | text value |
|---|---|
| Dial code | "" |
| Select 1 | "1" |
| Select 2 | "1*2" |
| Select 1 again | "1*2*1" |
3. Flask USSD Code – Walkthrough
Entry Point
@app.route("/ussd", methods=['POST'])
def ussd():This endpoint must be publicly accessible and respond quickly (<5 seconds).
Reading Request Parameters
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", "")text == ""→ first request in the session- Subsequent requests append input using
*
First Menu (Session Start)
if text == '':
response = "CON What would you want to check\n"
response += "1. My Account\n"
response += "2. My phone number"CONkeeps the session alive- Menu options must be plain text only
- Avoid special characters
Handling User Input
elif text == '1':User selected option 1 from the first menu.
elif text == '1*1':User navigated:
Menu 1 → Option 1 → Option 1This is how menu depth is inferred.
Ending the Session
response = "END Your phone number is " + phone_numberENDimmediately terminates the session- Any input after this is ignored
Important Rules
- Always return HTTP 200
- Response must start with CON or END
- HTTP 40X errors terminate the session automatically
4. Express (Node.js) Version – Same Logic
Your Express example follows the same principles:
app.post('/ussd', (req, res) => {Reading payload:
const { sessionId, serviceCode, phoneNumber, text } = req.body;Response headers:
res.set('Content-Type', 'text/plain');Africa’s Talking requires plain text responses.
5. Adding CBS (Community-Based Surveillance) Context
Now let’s adapt this USSD flow for a CBS reporting use case.
CBS Goal
Allow community members to:
- Report unusual illness
- Report deaths
- Report animal health events
- Submit reports without internet access
6. CBS USSD Menu Flow (Design)
Menu Structure
*384*123#
│
├── 1. Report Human Illness
│ ├── 1. Fever
│ ├── 2. Diarrhea
│ └── 3. Unknown illness
│
├── 2. Report Death
│ ├── 1. Adult
│ └── 2. Child
│
└── 3. Animal Health Event7. CBS USSD Example (Flask)
@app.route("/ussd", methods=['POST'])
def ussd():
text = request.values.get("text", "")
phone_number = request.values.get("phoneNumber")
if text == "":
response = "CON CBS Reporting\n"
response += "1. Report illness\n"
response += "2. Report death\n"
response += "3. Animal health event"
elif text == "1":
response = "CON Select illness type\n"
response += "1. Fever\n"
response += "2. Diarrhea\n"
response += "3. Unknown illness"
elif text == "1*1":
response = "END Thank you. Fever case reported.\nA health officer will follow up."
elif text == "1*2":
response = "END Thank you. Diarrhea case reported.\nA health officer will follow up."
elif text == "2":
response = "CON Report death\n"
response += "1. Adult\n"
response += "2. Child"
elif text == "2*1":
response = "END Adult death reported. Surveillance team notified."
elif text == "2*2":
response = "END Child death reported. Surveillance team notified."
else:
response = "END Invalid choice"
return response8. CBS Backend Integration (After USSD)
In production, instead of static messages, you would:
Store reports in a database
Trigger alerts to:
- Sub-county disease surveillance officers
- CHVs / CHEWs
Integrate with:
- DHIS2
- IDSR systems
- SMS follow-ups
9. Testing with Africa’s Talking Simulator
Steps:
Register at Africa’s Talking
Go to Sandbox
Create a USSD service
Assign a service code
Set callback URL to:
https://your-ngrok-linkUse the USSD Simulator:
https://developers.africastalking.com/simulator
10. Key CBS + USSD Best Practices
- Keep menus short and clear
- Avoid deep nesting (>3 levels)
- Use local language if possible
- Respond within <5 seconds
- Always acknowledge reports
- Provide feedback to build community trust
Conclusion
Africa’s Talking USSD provides a low-level, session-driven interface ideal for Community-Based Surveillance systems. By interpreting the text field correctly and managing session flow using CON and END, developers can build reliable, inclusive, and scalable CBS reporting tools that work on any mobile phone, even without internet access.