Skip to main content

Testing USSD Flows

Carrier provisioning is slow and live testing is costly, so validate your full flow in the sandbox first. This guide covers simulating sessions, asserting responses, and a pre-launch checklist.

๐Ÿš€ Quick Startโ€‹

Point your service code at the sandbox and dial the simulator.

curl -X POST https://api.afriroute.ai/api/v1/ussd/simulate \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"service_code": "*123#",
"phone": "+254712345678",
"text": ""
}'

The simulator calls your webhook exactly as a live gateway would and returns your CON/END reply.

๐Ÿงช Driving a Multi-Step Sessionโ€‹

Replay a sequence of keypresses by building up the text field, keeping the same session_id.

import requests

BASE = 'https://api.afriroute.ai/api/v1/ussd/simulate'
H = {'Authorization': 'Bearer $AFRIROUTE_API_KEY'}
sid = 'test-session-1'

def step(text):
r = requests.post(BASE, headers=H, json={
'session_id': sid, 'service_code': '*123#',
'phone': '+254712345678', 'text': text})
return r.json()['response']

assert step('').startswith('CON') # root menu
assert 'balance' in step('1').lower() # selected option 1

โœ… What to Assertโ€‹

CheckWhy
Root returns CONMenu renders on empty input
Each option routes correctlyNo mis-mapped digits
Terminal steps return ENDSessions close cleanly
Invalid input re-promptsNo dead ends
Screen length โ‰ค ~160 charsNo truncation
Response time < timeoutNo gateway drops
test('invalid input re-prompts', async () => {
const res = await simulate({ text: '9' });
expect(res).toMatch(/^CON/);
expect(res.toLowerCase()).toContain('invalid');
});

๐Ÿšฆ Pre-Launch Checklistโ€‹

  • All menu paths reach an END.
  • Invalid input handled at every step.
  • Money flows confirmed by SMS receipt.
  • State expires within the carrier session window.
  • Screens fit within character limits.
  • Webhook responds well under the timeout.
  • Tested with the live service_code once provisioned.

๐Ÿ’ก Best Practicesโ€‹

  • Automate flow tests so regressions are caught on every deploy.
  • Test the unhappy paths (timeouts, invalid keys) as much as the happy path.
  • Use a fixed session_id per test to keep runs deterministic.
  • Verify against the real service code before public launch.
  • Load-test the webhook โ€” gateways are unforgiving of latency.

Last Updated: May 2026