Skip to main content

SMS Best Practices

Getting an SMS delivered is more than calling the API. This guide covers the practical decisions — sender IDs, message length, encoding, timing, and compliance — that separate 60% delivery from 95%+.

🚀 Quick Start​

curl -X POST https://api.afriroute.ai/api/v1/sms/send \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+254712345678",
"from": "MyBrand",
"message": "Your order shipped! Reply STOP to opt out."
}'

📡 Deliverability Fundamentals​

Deliverability is driven by three things: a trusted sender ID, a clean message body, and good timing.

FactorImpactRecommendation
Registered sender IDHighRegister per-country before launch
Message contentMediumAvoid spam trigger words, shortened URLs
Send timingMediumLocal business hours, 8am–8pm
Number validationMediumValidate E.164 before sending
ThroughputLowSmooth bursts to avoid carrier filtering

✍️ Message Length & Encoding​

SMS is billed per segment. The segment size depends on the character set used.

EncodingSingle segmentPer segment (multipart)Trigger
GSM-7160 chars153 charsStandard Latin text
UCS-2 (Unicode)70 chars67 charsEmoji, Amharic, Arabic

A single emoji or an accented character switches the entire message to UCS-2, cutting your limit to 70 characters. Keep transactional messages in plain GSM-7 where possible.

def estimate_segments(message: str) -> int:
is_unicode = any(ord(c) > 127 for c in message)
if is_unicode:
return 1 if len(message) <= 70 else -(-len(message) // 67)
return 1 if len(message) <= 160 else -(-len(message) // 153)

🏷️ Sender IDs​

Use a registered alphanumeric sender ID (3–11 chars) for brand recognition and higher trust. Numeric shortcodes are required for two-way flows in some countries. See the dedicated Sender IDs guide.

const response = await fetch('https://api.afriroute.ai/api/v1/sms/send', {
method: 'POST',
headers: {
'Authorization': 'Bearer $AFRIROUTE_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: '+234803000000',
from: 'MyBank',
message: 'OTP 482913 expires in 5 min. Do not share.'
})
});

⏰ Timing & Throttling​

  • Send during local business hours (8am–8pm) for marketing.
  • Transactional (OTP, alerts) can send any time.
  • Spread large campaigns over minutes, not seconds, to avoid carrier rate filters.
  • Use scheduled_at to queue sends in the recipient's timezone.

🚫 Opt-Out & Compliance​

Marketing SMS must offer opt-out in most African markets.

  • Append Reply STOP to opt out to promotional messages.
  • Maintain a suppression list and never re-message opted-out numbers.
  • Keep consent records for audit.
if recipient in suppression_list:
skip() # never send to opted-out numbers

💡 Best Practices​

  • Register sender IDs per country before going live — unregistered IDs get filtered.
  • Keep messages under 160 GSM-7 characters to avoid multipart charges.
  • Avoid public URL shorteners — carriers flag them as spam.
  • Validate numbers with Lookup to cut wasted spend.
  • Track delivery webhooks instead of assuming success.
  • Send time-sensitive OTPs immediately, batch the rest.

Last Updated: May 2026