Skip to main content

SMS Send Flow

Overview

The SMS send flow describes how MALIPOPAY delivers transactional and marketing SMS to Tanzanian subscribers. Messages are routed through one of several provider adapters (Airtel, Africa's Talking, SMPP direct) based on the recipient's network and the merchant's configuration. All SMS are queued via BullMQ and delivered asynchronously with automatic failover.

Sequence diagram

sequenceDiagram
autonumber
participant M as Merchant App
participant API as SMS Service
participant Q as BullMQ Queue
participant W as SMS Worker
participant GW as SMS Gateway<br/>(Airtel / SMPP / AT)
participant C as Recipient
participant DLR as Delivery Report

M->>API: POST /sms/<br/>apiToken, sender, phone, message
API->>API: validate apiToken,<br/>balance, sender ID whitelist
API-->>M: 201 Accepted<br/>{ messageId, status: QUEUED }

API->>Q: enqueue with priority
Q->>W: job picked up
W->>GW: dispatch via operator
GW->>C: SMS delivered

alt Delivered
GW->>DLR: DLR success callback
DLR->>API: POST /sms/dlr { messageId, status: DELIVERED }
API->>M: webhook { messageId, status: DELIVERED }
else Failed (no credit, invalid number, expired)
GW->>DLR: DLR failure callback
DLR->>API: POST /sms/dlr { messageId, status: FAILED, reason }
API->>API: requeue (up to 3 attempts)
API->>M: webhook { messageId, status: FAILED, reason }
end

Key endpoints

StepEndpointNotes
1POST /sms/Send a single SMS. Returns immediately with QUEUED.
1bPOST /sms/bulkSend up to 10,000 recipients in one call. Same semantics, async delivery.
1cPOST /sms/flashSend a class-0 (flash) SMS. Appears on screen without being saved. Ideal for OTPs.
1dPOST /sms/scheduleSchedule SMS for future delivery. Takes sendAt ISO timestamp.
POST /sms/sms-statsPull delivery stats for a date range and sender ID.
GET /sms/{id}Fetch status of a specific message by messageId.

Channels and priority

Messages are prioritized in the queue by type:

TypePriorityTypical latency
otp1 (highest)< 3 s
transactional2< 10 s
notification3< 30 s
marketing / bulk4 (lowest)throttled per provider

OTPs bypass the marketing throttle to guarantee fast delivery. Bulk campaigns are throttled to 100 SMS/sec to respect operator rate limits.

Provider failover

If the primary provider fails (HTTP 5xx or no response in 15s), the SMS worker automatically retries via the secondary provider. The failover order is configurable per sender ID. Typical chain:

Airtel direct → Africa's Talking → SMPP fallback

After 3 failover attempts across providers, the message is marked FAILED and the merchant is charged zero.

Sender IDs

Every SMS must use a pre-approved sender ID. To register a new sender ID:

POST /company/sender-request
{ "senderId": "ACMECORP", "category": "TRANSACTIONAL" }

This enters the TCRA approval queue. Approval typically takes 1-3 business days. While pending, SMS attempts with that sender ID return HTTP 403 with code: 1101 (sender not approved).

Pricing

Per-SMS pricing is volume-tiered. Your current rate is visible in the dashboard and via:

GET /billing/rate

See the SMS pricing guide for the full tier table.