Advanced USSD Menu Builder with persistent state and navigation
npm install advanced-ussd-builder!npm version
!npm downloads
!license
!typescript
A powerful TypeScript library for building interactive USSD menus with persistent state management
Installation • Quick Start • Documentation • Examples • API
- Features
- Installation
- Quick Start
- Provider Support
- Core Concepts
- UssdMenu
- UssdBuilder
- Session Management
- Usage Examples
- Render Menu
- Render Menu with Function Handler
- Basic Menu
- Dynamic Menus
- Proxy Menu
- Handler Menus
- Conditional Menu Rendering
- API Reference
- Provider Integration
- MTN
- Nalo
- Telecel
- Airtel-Tigo
- Cross-Switch
- Custom Provider
- Advanced Features
- Session State Management
- Middleware Support
- Authentication Handler
- Proxy Service Integration
- Proxy Configuration Options
- Request Formats
- XML Payload Support
- Backend Implementation Examples
- Use Cases
- Path-based Handler Modules
- License
- 🚀 Multi-Provider Support - Works with MTN, Nalo, Telecel, Airtel-Tigo, Cross-Switch, and Custom providers
- 🔐 Built-in Authentication - PIN-based authentication with customizable handlers
- 🔌 Middleware Support - Request/response interceptors for logging, validation, and transformation
- 🎨 Custom Provider Setup - Easy integration with any USSD gateway through flexible configuration
- 🔀 Advanced Proxy Support - Forward requests to external USSD services with automatic network detection, flexible request formats (telco-specific or normalized), and custom transformations
- 💾 Persistent State Management - Redis-powered session management for stateful interactions
- 📱 Dynamic Menu Generation - Create menus programmatically with render and handler functions
- 🔄 Navigation History - Track and navigate through menu paths seamlessly
- 🎯 TypeScript Support - Full type definitions for better development experience
- ⚡ High Performance - Optimized for speed with minified production builds
- 🔧 Flexible Configuration - Customizable session prefixes, navigation keys, and more
``bash`
npm install advanced-ussd-builder
or using yarn:
`bash`
yarn add advanced-ussd-builder
- Node.js >= 14.x
- Redis server (for session management)
- TypeScript (for development)
`typescript
import { UssdBuilder, UssdMenu, iUssdMenu, iUssdMenuOptions, iMTNUSSDArgs } from 'advanced-ussd-builder';
// Define menu configuration
const menuOptions: iUssdMenuOptions = {
provider: 'mtn',
require_pin: false,
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
redis_connection_url: 'redis://localhost:6379',
state: {
user_id: '',
session_data: {}
}
};
// Create handler menus with path-based handlers
const registrationMenu: iUssdMenu = {
title: 'Register',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'root_menu',
handler: path.join(__dirname, '/handlers/registration.js')
};
// Create handler menus with function handlers
const balanceMenu: iUssdMenu = {
title: 'Check Balance',
type: 'handler',
handler_type: 'function',
handler: async (args) => {
const balance = await getUserBalance(args.msisdn);
return Your balance is $${balance};
}
};
// Create menu array
const menus = [registrationMenu, balanceMenu];
// Initialize USSD Builder with root menu
const ussdBuilder = new UssdBuilder(
menuOptions,
new UssdMenu('Welcome to MyApp', menus)
);
// Process USSD request (Express.js example)
app.post('/ussd/mtn', async (req, res) => {
const ussdArgs = req.body as iMTNUSSDArgs;
const sendResponse = (response) => {
return res.json(response);
};
await ussdBuilder.pipe<'mtn'>(ussdArgs, sendResponse);
});
`
Advanced USSD Builder supports multiple telecom providers out of the box:
| Provider | Status | Request Interface | Response Interface |
|----------|--------|------------------|-------------------|
| MTN | ✅ Supported | iMTNUSSDArgs | iMTNUssdCallback |iNaloUSSDArgs
| Nalo | ✅ Supported | | iNaloUssdCallback |iTelecelUssdArgs
| Telecel | ✅ Supported | | iTelecelUssdCallBack |iAirtelTigoUssdArgs
| Airtel-Tigo | ✅ Supported | | iAirtelTigoUssdCallBack |iCrossSwitchUssdArgs
| Cross-Switch | ✅ Supported | | iCrossSwitchUssdCallBack |
| Custom | ✅ Supported | Custom Interface | Custom Response |
The UssdMenu class represents a menu container that can hold multiple menu items. Each menu item follows the iUssdMenu interface structure.
`typescript
// Create a root menu with multiple options
const menuItems: iUssdMenu[] = [
{
title: 'Option 1',
type: 'handler',
handler_type: 'function',
handler: async (args) => {
return 'Response for option 1';
}
},
{
title: 'Option 2',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'default',
handler: './handlers/option2.js'
}
];
const rootMenu = new UssdMenu('Select an option:', menuItems);
`
The main orchestrator that manages menus, sessions, and request processing. It requires both configuration options and a root menu.
`typescript
const options: iUssdMenuOptions = {
provider: 'mtn', // or 'nalo', 'telecel', 'airtel-tigo', 'cross-switch', 'custom'
require_pin: false,
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
redis_connection_url: 'redis://localhost:6379',
state: {}, // Custom state object
middleware: async (args) => {
// Optional middleware
},
authentication_handler: async (args) => {
// Optional authentication
return true;
}
};
const builder = new UssdBuilder(options, rootMenu);
`
Sessions are automatically managed using Redis with the following structure:
- Session Key: {prefix}:{session_id}
- Session Data: Stores navigation path, current menu, and custom data
- TTL: Configurable time-to-live for session expiration
`typescript
// Render menu displays a list of options to the user
const renderMenus: iUssdMenu[] = [
{
title: 'Account Services',
type: 'render', // This will display as an option
render: {
success_message: 'Select an option:',
error_message: 'Invalid selection'
}
},
{
title: 'Transfer Money',
type: 'render',
render: {
success_message: 'Choose transfer type:'
}
},
{
title: 'Buy Airtime',
type: 'render',
render: {
success_message: 'Select amount:'
}
}
];
const ussdBuilder = new UssdBuilder(
options,
new UssdMenu('Main Menu\n1. Account Services\n2. Transfer Money\n3. Buy Airtime', renderMenus)
);
`
`typescript${idx + 1}. ${acc.name} - ${acc.balance}
// When type is 'render' with a handler, the handler controls the response
const dynamicRenderMenu: iUssdMenu = {
title: 'Account List',
type: 'render',
handler_type: 'function',
handler: async (args) => {
// Dynamically generate menu options
const accounts = await getUserAccounts(args.msisdn);
const menuOptions = accounts.map((acc, idx) =>
Your Accounts:\n${menuOptions}\n\nSelect account:
).join('\n');
// Handler returns the complete response
return {
message: ,`
continue_session: true
};
}
// No render object needed when handler is provided
};
`typescriptYour balance: $${balance}
const bankingMenus: iUssdMenu[] = [
{
title: 'Check Balance',
type: 'handler',
handler_type: 'function',
handler: async (args) => {
const balance = await getBalance(args.msisdn);
return ;
}
},
{
title: 'Transfer Funds',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'root_menu',
handler: './handlers/transfer.js'
},
{
title: 'Mini Statement',
type: 'handler',
handler_type: 'function',
handler: async (args) => {
const statement = await getStatement(args.msisdn);
return statement;
}
}
];
const ussdBuilder = new UssdBuilder(
options,
new UssdMenu('Welcome to Banking Services', bankingMenus)
);
`
`typescript
// Dynamically create menus based on user data
const createDynamicMenu = async (userPhone: string) => {
const user = await getUserData(userPhone);
const menuItems: iUssdMenu[] = [];
// Add different menus based on user status
if (user.isRegistered) {
menuItems.push({
title: 'My Account',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'root_menu',
handler: './handlers/account.js'
});
} else {
menuItems.push({
title: 'Register',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'root_menu',
handler: './handlers/registration.js'
});
}
return new UssdMenu('Welcome', menuItems);
};
// Use in request handler
app.post('/ussd', async (req, res) => {
const rootMenu = await createDynamicMenu(req.body.msisdn);
const builder = new UssdBuilder(options, rootMenu);
await builder.pipe<'mtn'>(req.body, (response) => res.json(response));
});
`
New in v2.4+: Enhanced proxy support with automatic network detection and flexible request formats.
#### Basic Proxy Configuration
`typescript`
// Simple proxy to external service
const basicProxy: iUssdMenu = {
title: 'Loan Services',
type: 'proxy',
proxy_config: {
target_url: 'https://loan-service.example.com/ussd',
timeout: 25000,
headers: {
'API-Key': process.env.LOAN_API_KEY
}
}
};
#### Telco-Specific Endpoints (Default Behavior)
`typescript`
// Forward requests in original telco format to telco-specific endpoints
const telcoSpecificProxy: iUssdMenu = {
title: 'Payment Service',
type: 'proxy',
proxy_config: {
target_url: 'https://payment.example.com/v1/ussd/mtn', // MTN-specific endpoint
// forward_original_format: true (default)
// Forwards MTN request format directly to the endpoint
}
};
#### Unified Endpoint with Network Detection
`typescript
// Use single endpoint for all networks with automatic network detection
const unifiedProxy: iUssdMenu = {
title: 'Unified Service',
type: 'proxy',
proxy_config: {
target_url: 'https://api.example.com/ussd', // Single endpoint for all networks
forward_original_format: false, // Use normalized format
// Network is automatically detected from phone number
}
};
// The proxy sends normalized request with network field:
// {
// msisdn: '0241234567',
// session_id: 'session-123',
// user_input: '1',
// service_code: '*123#',
// is_new_request: false,
// provider: 'mtn',
// network: 'MTN', // Auto-detected from phone number prefix
// session_data: {...},
// original_request: {...}
// }
`
#### Advanced Proxy with Transformations
`typescriptBearer ${process.env.TOKEN}
const advancedProxy: iUssdMenu = {
title: 'Insurance Portal',
type: 'proxy',
proxy_config: {
target_url: 'https://insurance.example.com/ussd',
forward_original_format: false,
timeout: 20000,
retry_attempts: 2,
retry_delay: 1500,
session_bridge: true, // Share session state
headers: {
'Authorization': ,`
'X-Partner-ID': 'partner-123'
},
// Custom request transformation
transform_request: (data) => ({
phone: data.msisdn,
network: data.network, // Includes auto-detected network
session: data.session_id,
input: data.user_input,
metadata: {
provider: data.provider,
timestamp: Date.now()
}
}),
// Custom response transformation
transform_response: (response) => ({
message: response.text,
require_feedback: response.continue
})
}
};
#### Custom Proxy Handler
`typescript`
// Use custom function instead of HTTP request
const customProxy: iUssdMenu = {
title: 'Custom Service',
type: 'proxy',
proxy_config: {
proxy_handler: async (builder, user_input) => {
// Custom logic here
const result = await customServiceCall(builder.session, user_input);
return {
message: result.display,
require_feedback: result.needsInput
};
}
}
};
#### Network Detection
The library automatically detects the network from Ghana phone numbers:
- MTN: 024, 054, 055, 059, 025
- Telecel: 020, 050
- AirtelTigo: 026, 056, 027, 057, 028
`typescript`
// Network detection works with various formats
getNetworkFromPhoneNumber('0241234567'); // Returns: 'MTN'
getNetworkFromPhoneNumber('233241234567'); // Returns: 'MTN'
getNetworkFromPhoneNumber('+233241234567'); // Returns: 'MTN'
getNetworkFromPhoneNumber('0201234567'); // Returns: 'TELECEL'
getNetworkFromPhoneNumber('0561234567'); // Returns: 'AIRTEL-TIGO'
// Combine local and proxy menus
const mainMenus: iUssdMenu[] = [
{
title: 'My Account',
type: 'handler',
handler_type: 'path',
handler: './handlers/account.js'
},
...proxyMenus // External services appear as regular menu items
];
const ussdBuilder = new UssdBuilder(
options,
new UssdMenu('Select Service:', mainMenus)
);
`
`typescriptYour balance: $${balance}\n\nPress 0 to go back
// Simple handler
const balanceHandler = new UssdMenu('check_balance', async (args) => {
const balance = await getBalance(args.msisdn);
return ;
});
// Handler with module path
const complexHandler = new UssdMenu('process_transfer', './handlers/transfer.js');
builder.register_menu(balanceHandler);
builder.register_menu(complexHandler);
`
Pagination is automatic when menu items exceed the configured limit:
`typescript
const builder = new UssdBuilder({
redis_url: 'redis://localhost:6379',
max_menu_items: 5 // Show 5 items per page
});
const largeMenu = new UssdMenu('products', 'Select Product');
// Adding more than 5 items will trigger pagination
for (let i = 1; i <= 20; i++) {
largeMenu.add_child(product_${i}, Product ${i});`
}
#### Constructor Options
`typescript`
interface UssdBuilderOptions {
redis_url: string; // Redis connection URL
session_prefix?: string; // Session key prefix for multi-instance isolation (default: 'ussd')
session_ttl?: number; // Session TTL in seconds (default: 120 seconds / 2 minutes)
max_menu_items?: number; // Max items per page (default: 5)
end_session_text?: string; // Custom end session message
}
#### Methods
| Method | Description | Parameters | Returns |
|--------|-------------|------------|---------|
| pipe | Process USSD request | args: provider args, callback: response handler | PromisegetSession()
| | Get current session | - | iUssdSession |saveSession()
| | Save session to Redis | - | PromiseendSession()
| | End current session | - | Promise
#### Constructor
`typescript`
new UssdMenu(
id: string,
title: string | Function | undefined,
opts?: {
custom_input?: boolean;
module_path?: string;
}
)
#### Menu Item Types
| Property | Description | Type |
|----------|-------------|------|
| title | Menu item display text | string |type
| | Menu type | 'render' \| 'handler' \| 'proxy' |handler_type
| | Handler type (for handler menus) | 'path' \| 'function' |handler
| | Handler implementation | string \| Function |handler_name_in_destination
| | Exported function name in module | string |proxy_config
| | Proxy configuration (for proxy menus) | ProxyConfig object |
`typescript`
app.post('/ussd/mtn', async (req, res) => {
const ussdArgs = req.body as iMTNUSSDArgs;
// Response callback
const sendResponse =
return res.json(response);
};
// Configure and build menu
const options: iUssdMenuOptions = {
provider: 'mtn',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL,
state: { / custom state / }
};
const menus: iUssdMenu[] = [/ your menus /];
const ussdBuilder = new UssdBuilder(
options,
new UssdMenu('Welcome', menus)
);
await ussdBuilder.pipe<'mtn'>(ussdArgs, sendResponse);
});
`typescript`
app.post('/ussd/nalo', async (req, res) => {
const ussdArgs = req.body as iNaloUSSDArgs;
const sendResponse =
return res.json(response);
};
const options: iUssdMenuOptions = {
provider: 'nalo',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL
};
const ussdBuilder = new UssdBuilder(options, rootMenu);
await ussdBuilder.pipe<'nalo'>(ussdArgs, sendResponse);
});
`typescript`
app.post('/ussd/telecel', async (req, res) => {
const ussdArgs = req.body as iTelecelUssdArgs;
const sendResponse =
return res.json(response);
};
const options: iUssdMenuOptions = {
provider: 'telecel',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL
};
const ussdBuilder = new UssdBuilder(options, rootMenu);
await ussdBuilder.pipe<'telecel'>(ussdArgs, sendResponse);
});
`typescript`
app.post('/ussd/at', async (req, res) => {
const ussdArgs = req.body as iAirtelTigoUssdArgs;
const sendResponse =
return res.json(response);
};
const options: iUssdMenuOptions = {
provider: 'airtel-tigo',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL
};
const ussdBuilder = new UssdBuilder(options, rootMenu);
await ussdBuilder.pipe<'airtel-tigo'>(ussdArgs, sendResponse);
});
`typescript`
app.post('/ussd/cross-switch', async (req, res) => {
const ussdArgs = req.body as iCrossSwitchUssdArgs;
const sendResponse =
return res.json(response);
};
const options: iUssdMenuOptions = {
provider: 'cross-switch',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL
};
const ussdBuilder = new UssdBuilder(options, rootMenu);
await ussdBuilder.pipe<'cross-switch'>(ussdArgs, sendResponse);
});
The library supports custom providers for any USSD gateway not listed above:
`typescript`
// Custom provider implementation
app.post('/ussd/custom', async (req, res) => {
const customArgs = {
msisdn: req.body.phoneNumber,
session_id: req.body.sessionId,
msg: req.body.userInput,
// Map your custom fields
};
const sendResponse = (response) => {
// Transform response to your custom format
const customResponse = {
text: response.message || response.msg,
continueSession: response.msgtype !== false,
sessionId: response.session_id
};
return res.json(customResponse);
};
const options: iUssdMenuOptions = {
provider: 'custom',
service_code: req.body.serviceCode,
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL,
make_provider_response: false, // Handle response formatting manually
state: {}
};
const menus: iUssdMenu[] = [/ your menus /];
const ussdBuilder = new UssdBuilder(
options,
new UssdMenu('Welcome', menus)
);
await ussdBuilder.pipe<'custom'>(customArgs, sendResponse);
});
`typescript
// Pass state through options that persists across menus
const options: iUssdMenuOptions = {
provider: 'mtn',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL,
state: {
user_id: '12345',
user_name: 'John Doe',
account_type: 'premium',
// Any custom data you need
}
};
// Access state in handlers
const menuHandler: iUssdMenu = {
title: 'Account Info',
type: 'handler',
handler_type: 'function',
handler: async (args) => {
// Access state passed through options
const userId = args.state?.user_id;
const userName = args.state?.user_name;
return Welcome ${userName}, your ID is ${userId};`
}
};
`typescript`
const options: iUssdMenuOptions = {
provider: 'mtn',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: false,
redis_connection_url: REDIS_URL,
middleware: async (args) => {
// Log every request
console.log('USSD Request:', args);
// Validate user
const user = await validateUser(args.msisdn);
if (!user) {
throw new Error('Unauthorized');
}
// Add user to args
args.user = user;
}
};
`typescript`
const options: iUssdMenuOptions = {
provider: 'mtn',
service_code: '*123#',
next_page_key: '#',
back_page_key: '0',
require_pin: true, // Enable PIN requirement
redis_connection_url: REDIS_URL,
authentication_handler: async (args) => {
// Custom authentication logic
const isValid = await validateUserPin(args.msisdn, args.input);
return isValid;
}
};
#### Proxy Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| target_url | string | - | URL of the target USSD service (required unless using proxy_handler) |forward_original_format
| | boolean | true | Forward telco-specific format or use normalized format |timeout
| | number | 25000 | Request timeout in milliseconds |retry_attempts
| | number | 1 | Number of retry attempts for failed requests |retry_delay
| | number | 1000 | Delay between retries in milliseconds |session_bridge
| | boolean | true | Share session state with target service |headers
| | object | {} | Additional HTTP headers to send |transform_request
| | function | - | Custom request transformation function |transform_response
| | function | - | Custom response transformation function |proxy_handler
| | function | - | Custom handler function instead of HTTP request |
#### Request Formats
##### 1. Original Telco Format (default)
`typescript
// Forwards the exact format from the telco
const telcoProxy: iUssdMenu = {
title: 'Service',
type: 'proxy',
proxy_config: {
target_url: 'https://api.example.com/v1/ussd/mtn',
forward_original_format: true // default
}
};
// MTN format example:
// {
// sessionId: 'session-123',
// messageType: '1',
// msisdn: '233241234567',
// ussdString: '1',
// serviceCode: '*123#',
// cellId: 'cell-id',
// imsi: 'imsi-id',
// ...
// }
`
##### 2. Normalized Format with Network Detection
`typescript
// Sends normalized format with auto-detected network
const normalizedProxy: iUssdMenu = {
title: 'Service',
type: 'proxy',
proxy_config: {
target_url: 'https://api.example.com/ussd', // Single endpoint
forward_original_format: false
}
};
// Normalized format:
// {
// msisdn: '0241234567',
// session_id: 'session-123',
// user_input: '1',
// service_code: '*123#',
// is_new_request: false,
// provider: 'mtn',
// network: 'MTN', // Auto-detected from phone number
// session_data: {...},
// original_request: {...} // Original telco request
// }
`
#### Backend Implementation Examples
##### Single Endpoint with Network Routing
`javascript`
// Express.js example
app.post('/ussd', (req, res) => {
const { network, msisdn, user_input, session_id } = req.body;
// Route based on detected network
switch(network) {
case 'MTN':
return handleMTN(req, res);
case 'TELECEL':
return handleTelecel(req, res);
case 'AIRTEL-TIGO':
return handleAirtelTigo(req, res);
default:
return handleUnknown(req, res);
}
});
##### Separate Telco Endpoints
`javascript
// MTN endpoint - receives MTN format
app.post('/v1/ussd/mtn', (req, res) => {
const { sessionId, msisdn, ussdString, messageType } = req.body;
// Handle MTN-specific format
});
// Telecel endpoint - receives Telecel format
app.post('/v1/ussd/telecel', (req, res) => {
const { sessionid, msisdn, msg, type } = req.body;
// Handle Telecel-specific format
});
`
#### XML Payload Support
The proxy handler automatically preserves XML payloads when forwarding requests to target endpoints. This is particularly important for Telecel and Airtel-Tigo providers which use XML formats.
##### XML Preservation Features
- Automatic Detection: Content-type headers are automatically detected and preserved
- Raw Body Forwarding: XML bodies are forwarded as-is without conversion to JSON
- Provider Support: Full support for Telecel and Airtel-Tigo XML formats
- Response Parsing: XML responses are properly parsed and converted to the expected format
##### Example: XML Provider Proxy
`typescript
// Telecel XML format proxy
const telecelProxy: iUssdMenu = {
title: 'Telecel Service',
type: 'proxy',
proxy_config: {
target_url: 'https://api.example.com/v1/ussd/telecel',
forward_original_format: true // Preserves XML format
}
};
// When receiving Telecel XML:
//
//
//
//
//
//
// The XML is forwarded as-is to the target endpoint
`
##### Example: Airtel-Tigo XML Support
`typescript
// Airtel-Tigo XML format proxy
const airtelTigoProxy: iUssdMenu = {
title: 'Airtel-Tigo Service',
type: 'proxy',
proxy_config: {
target_url: 'https://api.example.com/v1/ussd/airtel-tigo',
forward_original_format: true // Preserves XML format
}
};
// Airtel-Tigo XML with nested structure:
//
//
//
//
//
//
//
//
//
//
`
##### Backend Handling for XML
`javascript
// Express.js with XML body parser
const xmlParser = require('express-xml-bodyparser');
app.use(xmlParser());
app.post('/v1/ussd/telecel', (req, res) => {
// req.body contains parsed XML
const { msisdn, sessionid, msg, type } = req.body.request;
// Process and return XML response
res.set('Content-Type', 'text/xml');
res.send(
);`
});
#### Use Cases
- Third-party Integration: Connect to external USSD services (loans, insurance, payments)
- Microservices Architecture: Route to different backend services
- Partner Applications: Seamlessly integrate partner USSD applications
- Load Balancing: Distribute requests across multiple backends
- Network Portability: Handle users who port numbers between networks
- Testing: Easy testing with different network configurations
- XML Service Integration: Seamlessly integrate with XML-based USSD services
`typescriptBearer ${process.env.AUTH_TOKEN}
// Complete example with all features
const advancedProxyMenu: iUssdMenu = {
title: 'Payment Gateway',
type: 'proxy',
proxy_config: {
target_url: process.env.PAYMENT_API_URL,
forward_original_format: false, // Use normalized format
timeout: 25000,
retry_attempts: 2,
retry_delay: 1000,
session_bridge: true,
headers: {
'Authorization': ,`
'X-Partner-ID': 'partner-123'
},
transform_request: (data) => ({
phoneNumber: data.msisdn,
network: data.network, // Includes auto-detected network
sessionId: data.session_id,
userInput: data.user_input,
metadata: {
provider: data.provider,
detectedNetwork: data.network,
timestamp: Date.now()
}
}),
transform_response: (response) => ({
message: response.display_text,
require_feedback: response.await_input === true,
session_data: response.session_state
})
}
};
`typescriptWelcome ${userData.name}
// menu-handler.js - External handler module
export const root_menu = async (args) => {
// Handler logic
const userData = await fetchUserData(args.msisdn);
return ;
};
export const process_payment = async (args) => {
// Another handler in same module
return 'Payment processed';
};
// Usage in menu definition
const menus: iUssdMenu[] = [
{
title: 'User Info',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'root_menu', // Function to call
handler: path.join(__dirname, '/handlers/menu-handler.js')
},
{
title: 'Process Payment',
type: 'handler',
handler_type: 'path',
handler_name_in_destination: 'process_payment', // Different function
handler: path.join(__dirname, '/handlers/menu-handler.js')
}
];
``
This project is licensed under the MIT License - see the LICENSE file for details.
- GitHub: @iammohammedb
- Redis for reliable session management
- TypeScript for type safety
- Jest for testing framework
- All contributors and users of this library
- 🌐 Website: www.bashtech.solutions
- 📧 Email:
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
---
Made with ❤️ by the BashTech Solutions Team