SendSMSCommand
Overview
SendSMSCommand sends SMS notifications to mobile numbers with support for both direct message text and template-based rendering. It integrates with configured SMS providers (Infobip, Credit Siwtch, etc.) and automatically handles template rendering when templateId is provided.
When to Use
✅ Use SendSMSCommand for:
- Sending OTP (One-Time Password) codes
- Transaction alerts and notifications
- Account balance inquiries
- Appointment reminders
- Template-based promotional messages
- Automated SMS workflows in business processes
❌ Don't use for:
- Email notifications (use
SendMailCommand) - Long-form content (SMS has character limits)
- Real-time chat (use appropriate messaging API)
Syntax
Basic SMS (Direct Message)
var result = doCmd('SendSMSCommand', {
Data: {
messageBody: 'Your OTP code is 123456. Valid for 10 minutes.',
mobileNumber: '+2348012345678'
}
});
Template-Based SMS
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'OTP_SMS',
context: {
otpCode: '123456',
validityMinutes: 10,
customerName: context.customerName
},
mobileNumber: '+2348012345678',
providerCode: 'TWILLIO'
}
});
JSON Configuration
{
"commandName": "SendSMSCommand",
"parameters": {
"Data": {
"mobileNumber": "+2348012345678",
"messageBody": "Your transaction of NGN 50,000 was successful. Balance: NGN 125,000",
"providerCode": "AFRICAS_TALKING"
}
}
}
Parameters
Data Object
| Parameter | Type | Required | Description |
|---|---|---|---|
| mobileNumber | string | ✅ Yes | Recipient mobile number (E.164 format recommended) |
| messageBody | string | Conditional | SMS text content (required if no templateId) |
| templateId | string | Conditional | Template ID from HtmlTemplateDefinition table (required if no messageBody) |
| context | object | No | Data for template rendering (used with templateId) |
| providerCode | string | No | SMS provider code (defaults to tenant configuration) |
How It Works
1. Direct Message Flow
SendSMSCommand → SMS Provider API → Mobile Network → Recipient
2. Template-Based SMS Flow
SendSMSCommand
├─> Fetch HtmlTemplateDefinition (by templateId)
├─> RenderHtmlCommand (template + context)
├─> Strip HTML tags from rendered output
├─> Generated text becomes messageBody
└─> SMS Provider API → Mobile Network → Recipient
Note: When using templateId, the system:
- Fetches the template from
HtmlTemplateDefinitiontable - Renders the template using
RenderHtmlCommandwith providedcontext - Strips all HTML tags to get plain text
- Sends the resulting text as SMS
Return Value
Success Response
{
"isSuccessful": true,
"message": "SMS sent successfully",
"statusCode": 200,
"data": {
"statusCode": 200,
"transactionId": "SMS-2024-001",
"transactionRef": "Infobip-MSG-12345",
"responseCode": "0000"
}
}
Error Response
{
"isSuccessful": false,
"message": "Failed to send SMS: Invalid mobile number",
"statusCode": 400,
"data": {
"statusCode": 400,
"error": "Invalid phone number format"
}
}
Examples
Example 1: Simple OTP SMS
// Send OTP code
var otpCode = generateOTP(); // Returns: "456789"
var result = doCmd('SendSMSCommand', {
Data: {
messageBody: `Your OTP is ${otpCode}. Valid for 10 minutes. Do not share this code.`,
mobileNumber: context.customerPhone
}
});
if (result.isSuccessful) {
logger.info('OTP sent successfully: ' + result.data.transactionId);
// Store OTP for verification
doCmd('InsertTableCommand', {
Data: {
table: 'tblOTPLog',
values: {
CustomerId: context.customerId,
OTPCode: otpCode,
Phone: context.customerPhone,
SentDate: new Date(),
ExpiryDate: new Date(Date.now() + 10 * 60000), // 10 minutes
TransactionRef: result.data.transactionId
}
}
});
}
Example 2: Template-Based OTP SMS
// Use pre-defined SMS template
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'OTP_SMS_TEMPLATE',
context: {
bankName: 'ABC Bank',
otpCode: context.otpCode,
validityMinutes: 10,
purpose: 'login verification'
},
mobileNumber: context.customerPhone
}
});
// Template OTP_SMS_TEMPLATE in HtmlTemplateDefinition:
// {{bankName}}: Your OTP for {{purpose}} is {{otpCode}}. Valid for {{validityMinutes}} minutes. Do not share.
//
// Rendered output:
// ABC Bank: Your OTP for login verification is 123456. Valid for 10 minutes. Do not share.
Example 3: Transaction Alert
// Send transaction notification
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'TRANSACTION_ALERT',
context: {
transactionType: 'Debit',
amount: formatCurrency(context.amount),
balance: formatCurrency(context.newBalance),
reference: context.transactionRef,
date: formatDate(new Date())
},
mobileNumber: context.customerPhone
}
});
// Template TRANSACTION_ALERT:
// {{transactionType}} Alert: {{amount}} on {{date}}.
// Balance: {{balance}}.
// Ref: {{reference}}
Example 4: Account Balance Inquiry Response
// Respond to balance inquiry with template
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'BALANCE_INQUIRY_RESPONSE',
context: {
customerName: context.customerName,
accountNumber: maskAccountNumber(context.accountNumber),
availableBalance: formatCurrency(context.availableBalance),
ledgerBalance: formatCurrency(context.ledgerBalance),
timestamp: new Date().toLocaleString()
},
mobileNumber: context.customerPhone
}
});
// Template BALANCE_INQUIRY_RESPONSE:
// Dear {{customerName}},
// Acct: {{accountNumber}}
// Available: {{availableBalance}}
// Ledger: {{ledgerBalance}}
// As at {{timestamp}}
Example 5: Appointment Reminder
// Send appointment reminder with specific provider
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'APPOINTMENT_REMINDER',
context: {
customerName: context.customerName,
appointmentDate: context.appointmentDate,
appointmentTime: context.appointmentTime,
branchName: context.branchName,
purpose: context.appointmentPurpose
},
mobileNumber: context.customerPhone,
providerCode: 'TWILLIO' // Specify provider
}
});
// Template APPOINTMENT_REMINDER:
// Hi {{customerName}}, reminder: Your {{purpose}} appointment is on {{appointmentDate}} at {{appointmentTime}} at {{branchName}} branch.
Example 6: Loan Approval Notification
// Notify customer of loan approval
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'LOAN_APPROVAL_SMS',
context: {
customerName: context.customerFirstName,
loanAmount: formatCurrency(context.approvedAmount),
interestRate: context.interestRate + '%',
tenure: context.tenureMonths + ' months',
monthlyPayment: formatCurrency(context.monthlyInstallment)
},
mobileNumber: context.customerPhone
}
});
// Template LOAN_APPROVAL_SMS:
// Congratulations {{customerName}}! Your loan of {{loanAmount}} has been approved.
// Rate: {{interestRate}}, Tenure: {{tenure}}, Monthly: {{monthlyPayment}}.
// Check your email for details.
Example 7: Multi-Step Workflow with Template
// Complete OTP verification workflow
function sendOTPAndVerify(customerId, purpose) {
// 1. Generate OTP
var otpCode = Math.floor(100000 + Math.random() * 900000).toString();
// 2. Get customer details
var customer = doCmd('RetrieveCustomerByIdQuery', {
Data: { id: customerId }
});
if (!customer.isSuccessful) {
throw new Error('Customer not found');
}
// 3. Send OTP via SMS using template
var smsResult = doCmd('SendSMSCommand', {
Data: {
templateId: 'OTP_VERIFICATION_SMS',
context: {
customerName: customer.data.firstName,
otpCode: otpCode,
purpose: purpose,
validityMinutes: 10,
supportPhone: '+234800123456'
},
mobileNumber: customer.data.phoneNumber
}
});
if (smsResult.isSuccessful) {
// 4. Store OTP in database
doCmd('InsertTableCommand', {
Data: {
table: 'tblOTPVerification',
values: {
CustomerId: customerId,
OTPCode: otpCode,
Purpose: purpose,
PhoneNumber: customer.data.phoneNumber,
CreatedDate: new Date(),
ExpiryDate: new Date(Date.now() + 10 * 60000),
IsUsed: false,
SMSTransactionId: smsResult.data.transactionId
}
}
});
return {
success: true,
otpId: smsResult.data.transactionId
};
}
return {
success: false,
error: smsResult.message
};
}
Integration with RenderHtmlCommand
How Template Rendering Works
When you provide templateId, the system automatically:
- Fetches Template: Retrieves template from
HtmlTemplateDefinition - Renders with Context: Calls
RenderHtmlCommandinternally - Strips HTML: Removes any HTML tags (in case template has formatting)
- Sends SMS: Uses the plain text as message body
Manual Template Rendering (Optional)
// If you need to see rendered output before sending
var htmlResult = doCmd('RenderHtmlCommand', {
Data: {
template: 'Hi {{name}}, your balance is {{balance}}',
data: {
name: 'John',
balance: 'NGN 50,000'
}
}
});
// Then send as SMS
var smsResult = doCmd('SendSMSCommand', {
Data: {
messageBody: htmlResult.data.html,
mobileNumber: '+2348012345678'
}
});
Provider Configuration
Supported Providers
| Provider Code | Provider Name | Notes |
|---|---|---|
TWILLIO | Infobip | International SMS |
AFRICAS_TALKING | Credit Siwtch | Pan-African coverage |
TERMII | Termii | Nigerian SMS provider |
CUSTOM | Custom Provider | Configured in tenant settings |
Using Specific Provider
// Override default provider
var result = doCmd('SendSMSCommand', {
Data: {
messageBody: 'Test message',
mobileNumber: '+2348012345678',
providerCode: 'TWILLIO' // Use Infobip instead of default
}
});
Default Provider
If providerCode is not specified, the system uses the provider configured in tenant settings:
Configuration Key: SMSProvider
Default Value: TWILLIO
Use Cases
1. Two-Factor Authentication (2FA)
doCmd('SendSMSCommand', {
Data: {
templateId: '2FA_OTP',
context: { code: '123456', app: 'Internet Banking' },
mobileNumber: context.phone
}
});
2. Transaction Notifications
doCmd('SendSMSCommand', {
Data: {
templateId: 'DEBIT_ALERT',
context: {
amount: 'NGN 5,000',
balance: 'NGN 45,000'
},
mobileNumber: context.phone
}
});
3. Account Statements via SMS
doCmd('SendSMSCommand', {
Data: {
templateId: 'MINI_STATEMENT',
context: {
transactions: lastThreeTransactions
},
mobileNumber: context.phone
}
});
4. Marketing Campaigns
doCmd('SendSMSCommand', {
Data: {
templateId: 'PROMO_OFFER',
context: {
customerName: 'John',
offerDetails: '20% off on loans'
},
mobileNumber: context.phone
}
});
Error Handling
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "mobileNumber is required" | Missing phone number | Provide mobileNumber parameter |
| "messageBody or templateId required" | Missing both fields | Provide either messageBody or templateId |
| "Invalid phone number format" | Malformed number | Use E.164 format: +234XXXXXXXXXX |
| "Template not found" | Invalid templateId | Check HtmlTemplateDefinition table |
| "Provider not configured" | Invalid providerCode | Verify provider configuration |
| "SMS credits exhausted" | No SMS credits | Top up SMS credits with provider |
| "Number blacklisted" | Recipient opted out | Remove from SMS list |
Error Handling Example
try {
var result = doCmd('SendSMSCommand', {
Data: {
templateId: 'OTP_SMS',
context: { otpCode: '123456' },
mobileNumber: context.customerPhone
}
});
if (!result.isSuccessful) {
logger.error('SMS failed: ' + result.message);
// Retry with different provider
if (result.message.includes('Provider not available')) {
result = doCmd('SendSMSCommand', {
Data: {
templateId: 'OTP_SMS',
context: { otpCode: '123456' },
mobileNumber: context.customerPhone,
providerCode: 'AFRICAS_TALKING' // Fallback provider
}
});
}
// If SMS fails, try email as backup
if (!result.isSuccessful) {
doCmd('SendMailCommand', {
Data: {
subject: 'Your OTP Code',
email: [context.customerEmail],
message: '<p>Your OTP is 123456</p>'
}
});
}
}
} catch (error) {
logger.error('SMS error: ' + error.message);
}
Best Practices
1. Phone Number Validation
function isValidPhoneNumber(phone) {
// E.164 format: +[country code][number]
return /^\+[1-9]\d{1,14}$/.test(phone);
}
if (!isValidPhoneNumber(context.phone)) {
throw new Error('Invalid phone number format');
}
2. Message Length Optimization
// SMS has 160-character limit for single message
// Keep messages concise
var message = `OTP: ${otpCode}. Valid ${minutes}min.`; // Good
// vs
var message = `Dear valued customer, your one-time password is ${otpCode}...`; // Too long
3. Template Organization
- Store reusable SMS templates in HtmlTemplateDefinition
- Use consistent naming:
{MODULE}_{TYPE}_SMS - Keep templates under 160 characters for single SMS
- Example:
OTP_SMS,TRANSACTION_ALERT_SMS,BALANCE_INQUIRY_SMS
4. Context Preparation
// Prepare clean context
var smsContext = {
name: context.customerName || 'Customer',
amount: formatCurrency(context.amount),
code: context.otpCode.toString(),
time: new Date().toLocaleTimeString()
};
5. Rate Limiting
// Check if customer hasn't received too many SMS recently
var recentSMS = doCmd('GetFullTableQuery', {
Data: {
table: 'tblSMSLog',
filter: `CustomerId = ${context.customerId} AND SentDate > '${last5Minutes}'`
}
});
if (recentSMS.data.rows.length >= 3) {
throw new Error('Too many SMS requests. Please try again later.');
}
6. Audit Trail
// Log all SMS sent
if (result.isSuccessful) {
doCmd('InsertTableCommand', {
Data: {
table: 'tblSMSLog',
values: {
CustomerId: context.customerId,
PhoneNumber: context.phone,
MessageType: 'OTP',
SentDate: new Date(),
TransactionId: result.data.transactionId,
Provider: providerCode
}
}
});
}
Performance Tips
- Template Caching: Templates are cached after first load
- Provider Selection: Choose geographically appropriate provider
- Async Processing: SMS sending is asynchronous
- Bulk SMS: For multiple recipients, consider batch API
- Message Length: Keep under 160 characters to avoid split messages
Character Limits
| SMS Type | Character Limit | Notes |
|---|---|---|
| Standard SMS | 160 characters | GSM-7 encoding |
| Unicode SMS | 70 characters | For special characters/emojis |
| Concatenated SMS | 153 chars per part | Automatically split by provider |
Related Commands
- SendMailCommand - Send email notifications
- RenderHtmlCommand - Render message templates
InsertTableCommand- Log sent SMSGetFullTableQuery- Query SMS logs
API Endpoint
POST /api/bpm/execute-command
{
"commandName": "SendSMSCommand",
"parameters": {
"Data": {
"mobileNumber": "+2348012345678",
"messageBody": "Your OTP is 123456"
}
}
}
Configuration
Provider Settings
Configure SMS providers in tenant configuration:
- Provider API Keys
- Provider URLs
- Character encoding
- Delivery reports
- Fallback providers
Template Storage
SMS templates are stored in:
- HtmlTemplateDefinition table
- Template Type:
SMS - Plain text or simple HTML (stripped during sending)
Version History
- v2.0: Added templateId support with automatic RenderHtmlCommand integration
- v1.5: Added providerCode parameter for multi-provider support
- v1.0: Initial release with basic SMS functionality
See Also
- SMS Template Guide - Creating effective SMS templates
- OTP Implementation - Implementing OTP workflows
- Provider Configuration - Setting up SMS providers