Delivery Reports
Delivery reports (DLRs) provide real-time status updates on your sent messages, allowing you to track whether each message reached its recipient.
Delivery Statuses
| Status | Description |
|---|---|
PENDING | Message has been accepted and queued for delivery |
SENT | Message has been submitted to the mobile carrier |
DELIVERED | Message was successfully delivered to the recipient's device |
FAILED | Message delivery failed. Check the failure reason in the response |
EXPIRED | Message was not delivered within the carrier's time window |
Checking Delivery Status via API
Single Message
bash
curl -X GET https://api.galatext.com/api/sms/messages/msg_abc123def456 \
-H "x-api-key: YOUR_API_KEY"json
{
"success": true,
"data": {
"messageId": "msg_abc123def456",
"phoneNumber": "+254712345678",
"message": "Your OTP is 482916.",
"status": "DELIVERED",
"senderId": "YOURBRAND",
"segments": 1,
"creditsUsed": 1,
"deliveredAt": "2025-06-15T14:32:10Z",
"sentAt": "2025-06-15T14:32:05Z",
"createdAt": "2025-06-15T14:32:00Z"
}
}Batch Status
bash
curl -X GET https://api.galatext.com/api/sms/batches/batch_xyz789abc012 \
-H "x-api-key: YOUR_API_KEY"json
{
"success": true,
"data": {
"batchId": "batch_xyz789abc012",
"status": "COMPLETED",
"total": 100,
"delivered": 95,
"failed": 3,
"pending": 0,
"expired": 2,
"completedAt": "2025-06-15T14:35:00Z"
}
}Webhook Delivery Reports
For real-time updates, configure a webhook URL. Galatext will send a POST request to your endpoint when message statuses change.
Setup
- Go to Settings → Webhooks in the dashboard
- Click Add Webhook
- Enter your callback URL (e.g.,
https://your-app.com/webhooks/galatext) - Select Delivery Reports event type
- Optionally set a secret for signature verification
- Save the webhook
You can also set a per-message webhook URL by passing webhookUrl in the Send SMS request.
Payload Format
json
{
"event": "message.delivered",
"timestamp": "2025-06-15T14:32:10Z",
"data": {
"messageId": "msg_abc123def456",
"batchId": "batch_xyz789abc012",
"phoneNumber": "+254712345678",
"status": "DELIVERED",
"senderId": "YOURBRAND",
"reference": "order-12345",
"deliveredAt": "2025-06-15T14:32:10Z",
"creditsUsed": 1
}
}Event Types
| Event | Triggered When |
|---|---|
message.pending | Message accepted and queued |
message.sent | Message submitted to carrier |
message.delivered | Message delivered to recipient |
message.failed | Message delivery failed |
message.expired | Message expired before delivery |
Failure Reasons
When a message fails, the webhook payload includes a reason field:
json
{
"event": "message.failed",
"data": {
"messageId": "msg_failed123",
"phoneNumber": "+254712345678",
"status": "FAILED",
"reason": {
"code": "DESTINATION_NOT_REACHABLE",
"message": "Recipient phone is switched off or out of coverage"
}
}
}Common failure reasons:
| Code | Description |
|---|---|
INVALID_PHONE_NUMBER | Phone number not reachable |
DESTINATION_NOT_REACHABLE | Phone switched off or out of coverage |
NETWORK_ERROR | Carrier network issue |
BLACKLISTED | Recipient blocked or opted out |
INSUFFICIENT_BALANCE | Unable to route (carrier issue) |
EXPIRED | Message not delivered within validity period |
Retry Policy
For webhook delivery:
| Attempt | Delay |
|---|---|
| 1st | Immediate |
| 2nd | 30 seconds |
| 3rd | 2 minutes |
| 4th | 10 minutes |
| 5th | 30 minutes |
| Final | 2 hours |
After all attempts fail, the webhook event is discarded. Your endpoint should return 200 OK to acknowledge receipt.
Checking Delivery Rates
bash
curl -X GET https://api.galatext.com/api/sms/analytics/delivery-rates \
-H "x-api-key: YOUR_API_KEY"json
{
"success": true,
"data": {
"period": "last_7_days",
"totalSent": 15000,
"delivered": 14700,
"failed": 200,
"expired": 100,
"deliveryRate": 98.0,
"averageDeliveryTime": "3.2s"
}
}Best Practices
- Always store message IDs — Reference them for delivery tracking
- Set up webhooks — Get real-time updates instead of polling
- Monitor failure reasons — Identify and fix delivery issues quickly
- Track delivery rates — Use analytics to maintain high deliverability
- Handle retries — Your webhook endpoint should be idempotent