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

❌ Don'ts

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

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:

Data Integrity

1. Phone Number Validation

Always validate phone numbers before sending:

Format Requirements

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 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

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

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

Regulatory Compliance

1. GDPR & Data Protection

2. POPIA (South Africa)

3. Telecommunications Regulations (SADC)

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

Monitoring & Logging

1. What to Monitor

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:

Testing

1. Test Environment

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:

2. Message Best Practices

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

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:
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.