Skip to content

Customer USSD Guide

The customer USSD channel gives Emali 2.0 customers a fast, low-data way to access wallet services from any phone. Customer USSD runs on *123#, starts with language selection, remembers the customer's language preference, and asks for a PIN before sensitive actions.

Tip: Use USSD when the customer is on a feature phone, has poor data connectivity, or needs a quick assisted flow at an outlet or call center.

At a glance

Item Value
Dial code *123#
Audience Customers
Languages English and siSwati
Session identity MSISDN from the telco session
Sensitive-action auth Customer transaction PIN
Session timeout 5 minutes of inactivity
Test gateway https://api.test.emali2.damplabs.com/api/v1/ussd/sessions
Local gateway http://localhost:8805/ussd_gateway/api/v1/ussd/sessions

Customer menu

Option Action What the customer does
1 Check Balance View wallet balance after PIN verification
2 Send Money Enter recipient, amount, PIN, and confirm
3 Pay Bills Pick a recent/popular paybill when available, or enter the paybill manually
4 Buy Airtime Buy airtime for self after PIN confirmation
5 Mini Statement View the latest 5 transactions
6 My Account Change PIN, change language, view account info, limits, notifications
7 Cash Out Enter agent till, enter amount, enter PIN, confirm, and receive a withdrawal code
8 Requests & Support Review pending customer approvals and support-driven actions

Session lifecycle

  1. Customer dials *123#.
  2. The first screen asks for language: 1. English or 2. siSwati.
  3. The selected language is saved and reused in the rest of the session.
  4. The customer enters a PIN before sensitive views such as balance, mini statement, and approval actions.
  5. Transaction flows such as send money, pay bills, airtime, and cash out request the transaction PIN before confirmation.

Live menu examples

English

Language / Lulwimi

1. English
2. siSwati

Current / Manje: English

Select option / Khetsa:
EMALI MOBILE MONEY
1. Check Balance
2. Send Money
3. Pay Bills
4. Buy Airtime
5. Mini Statement
6. My Account
7. Cash Out
8. Requests & Support

siSwati

Language / Lulwimi

1. English
2. siSwati

Current / Manje: siSwati

Select option / Khetsa:
EMALI MOBILE MONEY
1. Bona Imali
2. Thumela Imali
3. Khokha Timbilisi
4. Thenga I-airtime
5. Statement Lencane
6. I-akhawunti Yami
7. Khipha Imali
8. Ticelo & Sekelo

Simulator request format

The telco simulator and Postman collection post JSON to /api/v1/ussd/sessions.

{
  "sessionId": "cust-balance-001",
  "msisdn": "+26870000001",
  "text": "",
  "serviceCode": "*123#",
  "networkCode": "ALL",
  "newSession": true
}

The response body is plain text. Use the same sessionId while the USSD session is still active.

If your gateway environment enforces request signing, include the X-Emali2-Ussd-Key header in the simulator request. Public test and local flows may not require it.

Flow examples

1. Start a session and choose siSwati

BASE_URL="https://api.test.emali2.damplabs.com/api/v1/ussd/sessions"
SESSION_ID="cust-ss-001"

curl -sS "$BASE_URL" \
  -H 'Content-Type: application/json' \
  -d '{
    "sessionId":"'"$SESSION_ID"'",
    "msisdn":"+26870000001",
    "text":"",
    "serviceCode":"*123#",
    "networkCode":"ALL",
    "newSession":true
  }'

curl -sS "$BASE_URL" \
  -H 'Content-Type: application/json' \
  -d '{
    "sessionId":"'"$SESSION_ID"'",
    "msisdn":"+26870000001",
    "text":"2",
    "serviceCode":"*123#",
    "networkCode":"ALL",
    "newSession":false
  }'

2. Check balance

The balance flow is language-aware and PIN-gated.

BASE_URL="https://api.test.emali2.damplabs.com/api/v1/ussd/sessions"
SESSION_ID="cust-balance-001"

# Start session
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"",
  "serviceCode":"*123#","networkCode":"ALL","newSession":true
}'

# Select English
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'

# Open balance
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'

# Enter customer PIN
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"123456",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'

3. Send money

Dial *123# -> choose language -> 2. Send Money
-> enter recipient MSISDN -> enter amount -> enter PIN -> confirm

Use this flow for person-to-person transfers. The recipient MSISDN must be valid for the configured customer network rules.

4. Pay bills

The pay-bills menu is intentionally short:

  • If the customer has recent or frequent billers, the top billers are shown first.
  • If there are no recent billers, the menu falls back to manual entry.
  • Manual entry is always the safe path for large biller catalogs.

Example manual flow:

Dial *123# -> choose language -> 3. Pay Bills
-> choose "Enter paybill manually"
-> enter paybill number
-> enter account number
-> enter amount
-> enter PIN
-> confirm

Example simulator sequence:

BASE_URL="https://api.test.emali2.damplabs.com/api/v1/ussd/sessions"
SESSION_ID="cust-bill-001"
MANUAL_OPTION="<option shown for Enter paybill manually>"

curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"",
  "serviceCode":"*123#","networkCode":"ALL","newSession":true
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"3",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"'"$MANUAL_OPTION"'",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"100100",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"04012345678",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"20",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"123456",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'

For a manual SWSC payment, replace 100100 with 200200 and use the account reference WTR-2024-00156.

5. Buy airtime

Dial *123# -> choose language -> 4. Buy Airtime
-> choose network -> choose self or other
-> choose amount -> enter PIN -> confirm

6. Mini statement

Mini statement returns the latest 5 customer transactions, for example:

Mini Statement
Balance: E12326.10

1. Debit -E5 11/03 20:48
2. Debit -E20 11/03 20:48
3. Debit -E20 11/03 20:48
4. Debit -E13 11/03 20:46
5. Debit -E5 11/03 20:46

This flow is PIN-gated because it exposes account activity.

7. Cash out

Customer cash out uses manual till entry so the menu does not need to return every registered agent.

Dial *123# -> choose language -> 7. Cash Out
-> enter agent till
-> enter amount
-> enter PIN
-> confirm
-> receive withdrawal code

Example simulator sequence:

BASE_URL="https://api.test.emali2.damplabs.com/api/v1/ussd/sessions"
SESSION_ID="cust-cashout-001"

curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"",
  "serviceCode":"*123#","networkCode":"ALL","newSession":true
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"7",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"000001",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"50",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"123456",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'
curl -sS "$BASE_URL" -H 'Content-Type: application/json' -d '{
  "sessionId":"'"$SESSION_ID"'","msisdn":"+26870000001","text":"1",
  "serviceCode":"*123#","networkCode":"ALL","newSession":false
}'

8. Requests and support

Use Requests & Support when a customer needs to approve a pending collection or another backend-driven request. The approval list is PIN-gated and the customer can approve or reject directly from USSD.

Security model

Important: The telco session identifies the customer by MSISDN, but sensitive data and money movement still require a valid customer PIN.

  • Language selection can happen before the customer enters a PIN.
  • Balance, mini statement, and request approvals require a PIN gate.
  • Send money, pay bills, airtime, and cash out ask for the transaction PIN before final confirmation.
  • Language can be changed later in My Account -> Change Language.

Error handling and troubleshooting

Symptom What it usually means What the customer should do
Invalid option The menu choice does not exist in the current screen Re-enter the option shown on screen
Incorrect PIN Wrong customer PIN Retry carefully; if repeated, reset through support or My Account flow
Agent not found with identifier Invalid till number during cash out Reconfirm the till number from the agent
Amount must be between E50 and E3000 Cash-out amount is outside allowed limits Enter a value inside the allowed range
Session restarted Session timed out after inactivity Dial again and restart the flow

Testing assets

  • Postman collection: Emali2_USSD_Gateway_Collection.json
  • Local environment: Emali2_USSD_Local.postman_environment.json
  • Remote environment: Emali2_USSD_Remote.postman_environment.json

For agent-side operations, continue with the Agent USSD Guide.