/api/v1/sms-api/messages/{message_id}/Get Message Status
Check the delivery status of a specific SMS message using its unique message ID. Track delivery progress, timestamps, and provider responses.
Authentication Required
This endpoint requires a Bearer token. Get your API key from your dashboard.
Message Status Lifecycle
pending
Message queued for delivery, awaiting processing
sent
Message submitted to carrier, delivery in progress
delivered
Message successfully delivered to recipient
failed
Delivery failed (invalid number, network issue, etc.)
rejected
Message rejected by carrier (blocked number, spam filter, etc.)
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
message_id | uuid | Required | The unique message ID returned when SMS was sent (path parameter) Example: f2672215-c20b-452a-9b6b-1ba51884c55e |
Note: The message_id is included in the URL path, not as a query parameter. You receive this ID when you send an SMS.
Code Examples
import requests
from typing import Optional
# Configuration
# Get your API key from: https://roycetalk.com
# Format: XXXX_XXXXXXXXXXXXXXXXXXXXXXXX_
API_BASE_URL = "https://roycetalk.com/api/v1/sms-api/messages"
BEARER_TOKEN = "XXXX_XXXXXXXXXXXXXXXXXXXXXXXX_"
def get_message_status(message_id: str) -> Optional[dict]:
"""
Get delivery status of a specific SMS message
Args:
message_id: The unique message ID returned when SMS was sent
Returns:
dict: API response with message status, or None on failure
"""
# Construct URL with message ID
url = f"{API_BASE_URL}/{message_id}/"
# Request headers with Bearer token
headers = {
"Authorization": f"Bearer {BEARER_TOKEN}",
}
try:
# Make GET request
response = requests.get(url, headers=headers)
# Check if request was successful
if response.status_code == 200:
result = response.json()
message = result['data']
print("✓ Message status retrieved!")
print(f"Message ID: {message['id']}")
print(f"Recipient: {message['recipient_phone']}")
print(f"Status: {message['status_display']}")
print(f"Sent at: {message['sent_at']}")
if message['delivered_at']:
print(f"Delivered at: {message['delivered_at']}")
print(f"SMS Units: {message['sms_units_consumed']}")
return result
elif response.status_code == 404:
error = response.json()
print(f"✗ Message Not Found: {error.get('message', 'Invalid message ID')}")
return None
elif response.status_code == 403:
error = response.json()
print(f"✗ Authentication Error: {error['error']['message']}")
return None
else:
print(f"✗ Unexpected Error: {response.status_code}")
print(response.text)
return None
except requests.exceptions.RequestException as e:
print(f"✗ Request failed: {str(e)}")
return None
def wait_for_delivery(message_id: str, max_attempts: int = 10, interval: int = 5):
"""
Poll message status until delivered or failed
Args:
message_id: The unique message ID
max_attempts: Maximum number of status checks
interval: Seconds to wait between checks
"""
import time
for attempt in range(max_attempts):
print(f"\nCheck {attempt + 1}/{max_attempts}...")
status_info = get_message_status(message_id)
if not status_info:
break
status = status_info['data']['status']
if status in ['delivered', 'failed', 'rejected']:
print(f"\n✓ Final status: {status}")
return status_info
if attempt < max_attempts - 1:
print(f"Status: {status} - waiting {interval}s...")
time.sleep(interval)
print("\n✗ Max attempts reached")
return None
# Example usage
if __name__ == "__main__":
# Check specific message
message_id = "f2672215-c20b-452a-9b6b-1ba51884c55e"
status = get_message_status(message_id)
# Or wait for delivery
# wait_for_delivery(message_id)Response Examples
{
"success": true,
"data": {
"id": "f2672215-c20b-452a-9b6b-1ba51884c55e",
"recipient_phone": "+254712345678",
"message_text": "Hello from RoyceBulkSMS API",
"sender_id": "RoyceLTD",
"status": "delivered",
"status_display": "Delivered",
"sms_units_consumed": 1,
"created_at": "2025-11-28T13:49:13.265444+00:00",
"sent_at": "2025-11-28T13:49:15.123456+00:00",
"delivered_at": "2025-11-28T13:49:20.789012+00:00",
"provider_message_id": "8290842",
"provider_response_description": "Success",
"metadata": {
"callback_url": "https://yourapp.com/webhooks/sms",
"client_ref": "order-12345"
}
},
"message": "Message status retrieved successfully",
"meta": {
"timestamp": "2025-11-28T14:30:00.000000+00:00",
"api_version": "v1"
},
"errors": []
}Response Fields
statusCurrent delivery status: pending, sent, delivered, failed, or rejected
created_atWhen the message was created/queued in our system
sent_atWhen the message was submitted to the carrier (null if still pending)
delivered_atWhen the message was delivered to recipient (null if not yet delivered)
provider_message_idCarrier's unique ID for this message (for carrier support inquiries)
metadataYour custom data (callback_url, client_ref) provided when sending
Common Use Cases
Best Practices
Use Webhooks for Real-Time Updates
Instead of polling this endpoint, provide a callback_url when sending SMS. You'll receive automatic delivery updates via webhook, which is more efficient.
Store Message IDs
Always store the message_id returned when sending SMS. This is your only way to check status later. Link it to your order/user IDs.
Handle Different Statuses
Delivery takes 5-30 seconds typically. If status is "pending" or "sent", check again after a few seconds. If "failed" or "rejected", review the error description.
Don't Poll Excessively
Avoid checking status every second. Use exponential backoff: check after 5s, 10s, 30s, 60s. Better yet, use webhooks to avoid polling entirely.
Tracking Multiple Messages
For bulk sends, use these endpoints instead of checking each message individually:
GET /batches/{batch_id}/Get status summary for entire batchGET /messages/?batch_id=...List all messages in a batch
Rate Limiting
Status checks count toward your API rate limits. For high-volume applications, use webhooks instead of polling to avoid hitting rate limits.