Best Practices & Guidelines
Follow these best practices to ensure secure, reliable, and compliant SMS messaging with SMSDESK.
Important: These guidelines help you build robust
integrations and maintain compliance with telecommunications regulations across SADC countries.
Security Best Practices
1. API Key Management
⚠️ Critical: Your API key is equivalent to your password. Treat it with the same level
of security.
✅ Do's
- Store securely: Use environment variables or secure vaults (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault)
- Rotate regularly: Change API keys every 90 days or immediately if compromised
- Use different keys: Separate keys for development, staging, and production
- Restrict access: Limit who can view or regenerate API keys
- Monitor usage: Track API key usage for unusual patterns
❌ Don'ts
- Never commit to Git: Don't include API keys in source code repositories
- Never hardcode: Don't embed keys directly in application code
- Never share: Don't send keys via email, Slack, or other messaging platforms
- Never log: Don't write API keys to application logs
- Never expose client-side: Don't include keys in JavaScript, mobile apps, or public APIs
Example: Secure Storage
# Environment variable (.env file - add to .gitignore)
SMSDESK_API_KEY=your-api-key-here
SMSDESK_BASE_URL=https://{host}
# Python example
import os
api_key = os.environ.get('SMSDESK_API_KEY')
# Node.js example
const apiKey = process.env.SMSDESK_API_KEY;
# .NET example
string apiKey = Environment.GetEnvironmentVariable("SMSDESK_API_KEY");
2. Transport Security
- Always use HTTPS: Never send requests over HTTP (unencrypted)
- Verify SSL certificates: Don't disable certificate validation
- Use TLS 1.2+: Ensure your client supports modern TLS versions
- Pin certificates (optional): For high-security applications, implement certificate pinning
3. Authentication Headers
✅ Recommended: Use header-based authentication instead of query parameters.
# Good - Header-based (recommended)
curl -H "X-API-Key: your-api-key" https://{host}/sms/2/messages
# Avoid - Query parameter (may appear in logs)
curl https://{host}/api/http/main.ashx?key=your-api-key
4. IP Whitelisting
Contact support to enable IP whitelisting for additional security:
- Restrict API access to specific IP addresses
- Ideal for server-to-server integrations
- Prevents unauthorized access even if API key is compromised
Data Integrity
1. Phone Number Validation
Always validate phone numbers before sending:
Format Requirements
- International format: Include country code (e.g., 264811234567)
- No special characters: Remove spaces, dashes, parentheses
- Length validation: 9-15 digits (varies by country)
- Country code validation: Verify valid country codes
Example: Phone Number Validation
// JavaScript validation
function validatePhoneNumber(phone, countryCode = '264') {
// Remove all non-numeric characters
phone = phone.replace(/\D/g, '');
// Add country code if missing
if (!phone.startsWith(countryCode)) {
if (phone.startsWith('0')) {
phone = countryCode + phone.substring(1);
} else {
phone = countryCode + phone;
}
}
// Validate length (9-15 digits)
if (phone.length < 9 || phone.length > 15) {
return { valid: false, error: 'Invalid phone number length' };
}
return { valid: true, normalized: phone };
}
2. Message Encoding
- GSM-7 encoding: Use standard GSM characters for 160 chars per SMS
- Unicode (UCS-2): Required for special characters, emojis (70 chars per SMS)
- URL encoding: Encode special characters in GET requests
- Character validation: Check for unsupported characters before sending
GSM-7 Character Set
Standard: A-Z a-z 0-9 @ £ $ ¥ è é ù ì ò Ç Ø ø Å å Δ _ Φ Γ Λ Ω Π Ψ Σ Θ Ξ
Special: ! " # ¤ % & ' ( ) * + , - . / : ; < = > ? ¡ Ä Ö Ñ Ü § ¿ ä ö ñ ü à
Extended (2 chars): ^ { } \ [ ~ ] | €
3. Duplicate Prevention
Implement idempotency to prevent duplicate messages:
// Use unique reference IDs
const messageRef = `ORDER-${orderId}-${Date.now()}`;
await sendSMS({
to: customer.phone,
message: 'Your order has been confirmed',
ref: messageRef // Prevents duplicates
});
4. Data Sanitization
- Remove PII from logs: Don't log full phone numbers or message content
- Sanitize inputs: Validate and clean all user inputs
- Escape special characters: Prevent injection attacks
Performance Optimization
1. Batch Processing
✅ Recommended: Use bulk endpoints for sending multiple messages.
// Good - Bulk send (1 API call)
POST /sms/2/messages
{
"messages": [
{ "to": "264811234567", "text": "Message 1" },
{ "to": "264812345678", "text": "Message 2" },
{ "to": "264813456789", "text": "Message 3" }
]
}
// Avoid - Individual sends (3 API calls)
for (const recipient of recipients) {
await sendSMS(recipient); // Slow!
}
2. Asynchronous Processing
- Use async/await: Don't block on API calls
- Queue messages: Use message queues (RabbitMQ, Redis) for high volume
- Background jobs: Process bulk sends in background workers
- Webhooks: Use delivery report webhooks instead of polling
3. Connection Pooling
// Good - Reuse HTTP client
const httpClient = new HttpClient(); // Create once
httpClient.DefaultRequestHeaders.Add("X-API-Key", apiKey);
// Avoid - Creating new client each time
for (const msg of messages) {
const client = new HttpClient(); // Wasteful!
await client.PostAsync(...);
}
4. Caching
- Cache API responses: Store delivery reports, account info
- Cache validation results: Phone number validation, blacklist checks
- Set appropriate TTL: Balance freshness vs performance
Regulatory Compliance
1. GDPR & Data Protection
- Consent: Obtain explicit consent before sending marketing messages
- Data minimization: Only collect necessary phone numbers
- Right to erasure: Implement opt-out and data deletion
- Data retention: Don't store messages longer than necessary
- Privacy policy: Clearly state how you use phone numbers
2. POPIA (South Africa)
- Lawful processing: Have legal basis for processing personal information
- Purpose specification: Use phone numbers only for stated purpose
- Opt-out mechanism: Provide easy way to unsubscribe
- Security measures: Implement appropriate safeguards
3. Telecommunications Regulations (SADC)
- Sender ID registration: Register alphanumeric sender IDs with operators
- Content restrictions: No spam, fraud, or illegal content
- Time restrictions: Avoid sending between 21:00 - 08:00 (local time)
- Opt-out compliance: Honor STOP/UNSUBSCRIBE requests immediately
4. Industry-Specific Regulations
| Industry | Regulation | Requirements |
|---|---|---|
| Healthcare | HIPAA (US), POPIA | Encrypt PHI, obtain consent, audit logs |
| Finance | PCI-DSS, Banking Acts | No credit card numbers, secure OTPs |
| Education | FERPA, POPIA | Protect student data, parental consent |
| Marketing | GDPR, POPIA, CAN-SPAM | Opt-in consent, easy opt-out |
Error Handling
1. Retry Logic
async function sendWithRetry(message, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const result = await sendSMS(message);
return result;
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt - 1) * 1000;
await sleep(delay);
console.log(`Retry attempt ${attempt} after ${delay}ms`);
}
}
}
2. Error Classification
| Error Type | Action | Retry? |
|---|---|---|
| Network timeout | Retry with backoff | ✅ Yes |
| Rate limit (429) | Wait and retry | ✅ Yes |
| Server error (500) | Retry with backoff | ✅ Yes |
| Invalid phone (400) | Log and skip | ❌ No |
| Unauthorized (401) | Check API key | ❌ No |
| Insufficient credit | Alert admin | ❌ No |
3. Graceful Degradation
- Fallback mechanisms: Queue messages if API is down
- Circuit breaker: Stop retrying after repeated failures
- Alternative channels: Email as fallback if SMS fails
- User notification: Inform users of delivery issues
Monitoring & Logging
1. What to Monitor
- Success rate: Percentage of successfully sent messages
- Delivery rate: Percentage of delivered messages
- Response time: API latency and performance
- Error rate: Failed requests and reasons
- Credit balance: Remaining SMS credits
- Queue depth: Pending messages in queue
2. Logging Best Practices
// Good logging (masked sensitive data)
logger.info('SMS sent', {
messageId: '12345',
recipient: '264****4567', // Masked
status: 'PENDING',
timestamp: new Date().toISOString()
});
// Bad logging (exposes PII)
logger.info('SMS sent to 264811234567: "Your OTP is 123456"'); // Don't do this!
3. Alerting
Set up alerts for:
- High error rate: > 5% failed requests
- Low credit balance: < 1000 credits remaining
- API downtime: Service unavailable
- Unusual volume: Spike in message volume (possible abuse)
- Delivery failures: High rate of undelivered messages
Testing
1. Test Environment
- Separate API keys: Use different keys for dev/staging/production
- Test phone numbers: Use your own numbers for testing
- Mock responses: Create mock API for unit tests
- Sandbox mode: Contact support for sandbox access
2. Test Scenarios
| Scenario | Test Case | Expected Result |
|---|---|---|
| Valid message | Send to valid number | Success response, message delivered |
| Invalid number | Send to invalid format | Error response, clear error message |
| Long message | Send 500 character message | Split into multiple SMS parts |
| Unicode message | Send with emojis | Delivered correctly, 70 chars/SMS |
| Network error | Simulate timeout | Retry logic triggered |
| Insufficient credit | Send with zero balance | Error response, no charge |
Rate Limits
Default Limits
| Endpoint | Limit | Window |
|---|---|---|
| Send SMS (single) | 10 requests/second | Per API key |
| Send SMS (bulk) | 100 messages/request | Per request |
| Delivery reports | 100 requests/minute | Per API key |
| Incoming messages | 60 requests/minute | Per API key |
ℹ️ Need Higher Limits? Contact support to discuss enterprise rate limits for
high-volume applications.
Handling Rate Limits
if (response.status === 429) {
const retryAfter = response.headers['Retry-After'] || 60;
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
await sleep(retryAfter * 1000);
// Retry request
}
Message Content Guidelines
1. Prohibited Content
⚠️ Prohibited: The following content types are strictly forbidden:
- Spam: Unsolicited bulk messages
- Fraud: Phishing, scams, impersonation
- Illegal content: Drugs, weapons, illegal services
- Adult content: Pornography, explicit material
- Hate speech: Discrimination, harassment
- Malware: Malicious links or attachments
2. Message Best Practices
- Clear sender ID: Use recognizable business name
- Concise content: Keep messages brief and actionable
- Include opt-out: Add "Reply STOP to unsubscribe" for marketing
- Personalization: Use recipient's name when appropriate
- Call to action: Make next steps clear
- Timing: Send during business hours (08:00 - 21:00)
3. Message Templates
// Transactional (OTP)
"Your verification code is 123456. Valid for 10 minutes. Do not share."
// Order confirmation
"Hi John, your order #12345 has been confirmed. Delivery by Friday. Track: https://short.link/abc"
// Appointment reminder
"Reminder: Dental appointment tomorrow at 2:30 PM. Reply C to confirm or R to reschedule."
// Marketing (with opt-out)
"Flash Sale! 50% off all items today only. Shop now: https://shop.link Reply STOP to opt out"
Opt-Out Management
1. Implementing Opt-Out
- Keyword support: Accept STOP, UNSUBSCRIBE, CANCEL, QUIT
- Immediate processing: Honor opt-out requests within 24 hours
- Confirmation message: Send confirmation of opt-out
- Persistent storage: Maintain blacklist across all campaigns
- Re-subscription: Allow users to opt back in with START/SUBSCRIBE
2. Blacklist Management
// Check blacklist before sending
async function sendSMS(recipient, message) {
if (await isBlacklisted(recipient)) {
console.log(`Skipping blacklisted number: ${recipient}`);
return { status: 'BLACKLISTED', skipped: true };
}
return await apiClient.send({ to: recipient, text: message });
}
// Process opt-out request
async function handleOptOut(phoneNumber) {
await addToBlacklist(phoneNumber);
await sendConfirmation(phoneNumber,
"You have been unsubscribed. Reply START to re-subscribe.");
}
3. Compliance Checklist
✅ Opt-Out Compliance Checklist:
- ✅ Include opt-out instructions in marketing messages
- ✅ Process opt-out requests within 24 hours
- ✅ Send confirmation of opt-out
- ✅ Maintain centralized blacklist
- ✅ Check blacklist before every send
- ✅ Allow re-subscription
- ✅ Document opt-out procedures
- ✅ Train staff on opt-out handling
Need Help? Contact our support team for assistance
with implementing these best practices or if you have questions about compliance.
📋 Legal Notice: These guidelines are for informational purposes. You are responsible
for ensuring compliance with all applicable laws and regulations in your jurisdiction. See our Terms & Conditions for full legal
terms.
