This document provides concrete example payloads for testing USSD applications built with the Tech231 DSL.
Sample Banking Application
First, let's define a simple banking application DSL:
app "SimpleBanking" {
shortcode = "*888#"
version = "1.0.0"
start = "MainMenu"
options {
global_actions {
back_key = "0"
home_key = "00"
}
}
env = {
http_base_url = "https://api.simplebank.com"
}
# NOTE: The 'text' property is the header/prompt ONLY.
# Options are automatically rendered by the gateway adapter.
# Do NOT include option numbers in the text!
menu "MainMenu" {
text = "Welcome to Simple Bank"
option "1" {
label = "Check Balance"
goto = "BalanceResult"
}
option "2" {
label = "Transfer Money"
goto = "TransferAmount"
}
option "3" {
label = "Mini Statement"
goto = "StatementResult"
}
}
menu "BalanceResult" {
text = "Your balance is: ${ {response.balance} } \n Available: ${ {response.available} } "
terminal = true
}
menu "TransferAmount" {
text = "Enter amount to transfer:"
option "*" {
label = "Amount"
goto = "TransferRecipient"
actions = [
{ type = "set" , name = "save-amount" , target = "transfer_amount" , value = "{{session.input}}" }
]
}
}
menu "TransferRecipient" {
text = "Enter recipient phone number:"
option "*" {
label = "Recipient"
goto = "TransferConfirm"
actions = [
{ type = "set" , name = "save-recipient" , target = "recipient" , value = "{{session.input}}" }
]
}
}
menu "TransferConfirm" {
text = "Transfer ${ {session.data.transfer_amount} } to {{session.data.recipient}}?"
option "1" {
label = "Confirm"
goto = "TransferResult"
}
option "2" {
label = "Cancel"
goto = "MainMenu"
}
}
menu "TransferResult" {
text = "Transfer successful! \n Ref: {{response.reference}}"
terminal = true
}
menu "StatementResult" {
text = "Recent transactions: \n {{response.transactions}}"
terminal = true
}
menu "Goodbye" {
text = "Thank you for banking with us!"
terminal = true
}
}
Example Request Payloads
1. Session Initiation (New Session)
Request:
POST /api/v1/ussd/inbound
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
X-Request-ID: req-001-init
{
"sessionId": "sess-2024-001-abc123",
"msisdn": "231881234567",
"shortCode": "*888#",
"provider": "Orange",
"input": "",
"requestType": "initiation"
}
Expected Response (HTTP 200):
{
"sessionId" : "sess-2024-001-abc123" ,
"text" : "Welcome to Simple Bank \n 1. Check Balance \n 2. Transfer Money \n 3. Mini Statement \n 0. Back" ,
"endSession" : false ,
"currentState" : "MainMenu" ,
"traceId" : "0af7651916cd43dd8448eb211c80319c"
}
Note: The response text includes formatted options because the gateway adapter automatically renders them from the menu definition. The DSL text property only contains the header.
Request:
POST /api/v1/ussd/inbound
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"sessionId": "sess-2024-001-abc123",
"msisdn": "231881234567",
"shortCode": "*888#",
"provider": "Orange",
"input": "1",
"requestType": "continuation"
}
Expected Response (HTTP 200):
{
"sessionId" : "sess-2024-001-abc123" ,
"text" : "Your balance is: $1,234.56 \n Available: $1,200.00" ,
"endSession" : true ,
"currentState" : "BalanceResult" ,
"traceId" : "1bf8762027de54ee9559fc322d91420d"
}
3. Multi-Step Flow: Transfer Money
Step 1: Select Transfer
{
"sessionId" : "sess-2024-002-transfer" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "2" ,
"requestType" : "continuation"
}
Response:
{
"sessionId" : "sess-2024-002-transfer" ,
"text" : "Enter amount to transfer:" ,
"endSession" : false ,
"currentState" : "TransferAmount"
}
Step 2: Enter Amount (Wildcard Input)
{
"sessionId" : "sess-2024-002-transfer" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "50" ,
"requestType" : "continuation"
}
Response:
{
"sessionId" : "sess-2024-002-transfer" ,
"text" : "Enter recipient phone number:" ,
"endSession" : false ,
"currentState" : "TransferRecipient"
}
Step 3: Enter Recipient
{
"sessionId" : "sess-2024-002-transfer" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "231889876543" ,
"requestType" : "continuation"
}
Response:
{
"sessionId" : "sess-2024-002-transfer" ,
"text" : "Transfer $50 to 231889876543? \n 1. Confirm \n 2. Cancel" ,
"endSession" : false ,
"currentState" : "TransferConfirm"
}
Step 4: Confirm Transfer
{
"sessionId" : "sess-2024-002-transfer" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "1" ,
"requestType" : "continuation"
}
Response:
{
"sessionId" : "sess-2024-002-transfer" ,
"text" : "Transfer successful! \n Ref: TRF-2024-001234" ,
"endSession" : true ,
"currentState" : "TransferResult"
}
4. Global Back Navigation
Scenario: User is at TransferRecipient and presses "0" (back)
{
"sessionId" : "sess-2024-003-back" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "0" ,
"requestType" : "continuation"
}
Response (returns to TransferAmount):
{
"sessionId" : "sess-2024-003-back" ,
"text" : "Enter amount to transfer:" ,
"endSession" : false ,
"currentState" : "TransferAmount"
}
5. Global Home Navigation
Scenario: User is deep in menu hierarchy and presses "00" (home)
{
"sessionId" : "sess-2024-004-home" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "00" ,
"requestType" : "continuation"
}
Response (returns to MainMenu):
{
"sessionId" : "sess-2024-004-home" ,
"text" : "Welcome to Simple Bank \n 1. Check Balance \n 2. Transfer Money \n 3. Mini Statement \n 0. Back" ,
"endSession" : false ,
"currentState" : "MainMenu"
}
Scenario: User selects Exit from MainMenu
{
"sessionId" : "sess-2024-005-exit" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "0" ,
"requestType" : "continuation"
}
Response (session ends):
{
"sessionId" : "sess-2024-005-exit" ,
"text" : "Thank you for banking with us!" ,
"endSession" : true ,
"currentState" : "Goodbye"
}
Error Response Examples
Invalid MSISDN Format
// Request
{
"sessionId" : "sess-error-001" ,
"msisdn" : "invalid" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"requestType" : "initiation"
}
Response (HTTP 400):
{
"sessionId" : "sess-error-001" ,
"text" : "MSISDN must be 10-15 digits" ,
"endSession" : true ,
"error" : {
"code" : "INVALID_MSISDN" ,
"message" : "MSISDN must be 10-15 digits"
}
}
Application Not Found
// Request
{
"sessionId" : "sess-error-002" ,
"msisdn" : "231881234567" ,
"shortCode" : "*999#" ,
"provider" : "Orange" ,
"requestType" : "initiation"
}
Response (HTTP 404):
{
"sessionId" : "sess-error-002" ,
"text" : "No application found for this shortcode" ,
"endSession" : true ,
"error" : {
"code" : "APP_NOT_FOUND" ,
"message" : "No application found for this shortcode"
}
}
Session Not Found
// Request for expired/invalid session
{
"sessionId" : "sess-nonexistent" ,
"msisdn" : "231881234567" ,
"shortCode" : "*888#" ,
"provider" : "Orange" ,
"input" : "1" ,
"requestType" : "continuation"
}
Response (HTTP 404):
{
"sessionId" : "sess-nonexistent" ,
"text" : "Session not found or expired" ,
"endSession" : true ,
"error" : {
"code" : "SESSION_NOT_FOUND" ,
"message" : "Session not found or expired"
}
}
cURL Examples
Start a Session
curl -X POST "https://api.tech231.com/api/v1/ussd/inbound" \
-H "Authorization: Bearer $JWT_TOKEN " \
-H "Content-Type: application/json" \
-d '{
"sessionId": "test-session-001",
"msisdn": "231881234567",
"shortCode": "*888#",
"provider": "Orange",
"requestType": "initiation"
}'
Process User Input
curl -X POST "https://api.tech231.com/api/v1/ussd/inbound" \
-H "Authorization: Bearer $JWT_TOKEN " \
-H "Content-Type: application/json" \
-d '{
"sessionId": "test-session-001",
"msisdn": "231881234567",
"shortCode": "*888#",
"provider": "Orange",
"input": "1",
"requestType": "continuation"
}'
Alternative Session API
For direct session management (bypassing shortcode resolution):
Start Session (Session API)
POST /api/v1/ussd/session
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"msisdn": "231881234567",
"shortCode": "*888#",
"applicationName": "SimpleBanking",
"gateway": "Orange"
}
Process Input (Session API)
POST /api/v1/ussd/session/{sessionId}/input
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"input": "1"
}
Get Session State
GET /api/v1/ussd/session/{sessionId}
Authorization: Bearer {jwt_token}
Terminate Session
DELETE /api/v1/ussd/session/{sessionId}
Authorization: Bearer {jwt_token}
Provider-Specific Considerations
Provider MSISDN Format Session ID Format Notes Orange E.164 (231...) UUID or provider-assigned MTN E.164 (231...) Numeric sequence Lonestar E.164 (231...) Alphanumeric
See Also
Last modified on January 26, 2026