SMS-C API Reference
← Back to Documentation Index | Main README
Complete reference for all SMS-C REST API endpoints with request/response examples.
Table of Contents
- API Overview
- Authentication
- Common Response Formats
- Status Endpoint
- Message Queue API
- Raw SMS PDU API
- Location Management API
- Frontend Registration API
- Campaigns API
- Event Logging API
- MMS Message API
- SS7 Event API
- Error Codes
- Rate Limiting
- Best Practices
API Overview
The SMS-C REST API provides programmatic access to message submission, routing, and management functions.
Base URL
https://api.example.com:8443/api
Default Port: 8443 (configurable) Protocol: HTTPS (TLS required in production)
Content Type
All requests and responses use JSON:
Content-Type: application/json
API Versioning
The current API is version 1 (implicit). Future versions will use URL versioning:
https://api.example.com:8443/api/v2/...
Authentication
TLS Client Certificates (Recommended)
Production deployments should use TLS client certificate authentication:
curl --cert client.crt --key client.key \
https://api.example.com:8443/api/status
API Key Authentication
Custom API key authentication via X-API-Key header:
curl -H "X-API-Key: your_api_key_here" \
https://api.example.com:8443/api/status
IP Whitelisting
Restrict API access to trusted IP addresses at the firewall level.
Common Response Formats
Success Response
{
"data": {
...
}
}
Error Response
{
"errors": {
"detail": "Error message describing what went wrong"
}
}
List Response
{
"data": [
{...},
{...}
]
}
Status Endpoint
Health check endpoint for monitoring and load balancers.
Get API Status
Request:
GET /api/status
Response (200 OK):
{
"status": "ok",
"application": "OmniMessage",
"timestamp": "2025-10-30T12:34:56Z"
}
Example:
curl https://api.example.com:8443/api/status
Use Cases:
- Load balancer health checks
- Monitoring system connectivity
- Service availability verification
Message Queue API
Core message submission and management endpoints.
List Messages
Retrieve messages from the queue.
Request:
GET /api/messages
Optional Headers:
smsc: frontend_name- Filter by destination SMSCinclude-unrouted: true|false|1|0- Include messages without location registration (default: false)false(default): Only return messages with explicit routing or location registrationtrue: Include messages without location registration (backward compatible mode)
Query Parameters (list mode — only when no smsc header is sent):
status- Filter by a single status (default: all). One of:queued,backoff,sent,delivered,expired,dropped,auto_replied,balance_rejected,deletedlimit- Max records to return (default: 100, max: 1000)offset- Records to skip for pagination (default: 0)
Results are returned newest-first by message id. The endpoint is paginated by
default: without limit it returns at most 100 records, never the whole store.
Response (200 OK) — a JSON array of messages:
[
{
"id": 12345,
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_text": "Hello World",
"source_smsc": "api_client",
"dest_smsc": "uk_gateway",
"status": "queued",
"send_time": "2025-10-30T12:00:00Z",
"deliver_time": null,
"delivery_attempts": 0,
"inserted_at": "2025-10-30T12:00:00Z"
}
]
Examples:
Get pending messages for specific SMSC (only with explicit routing or location):
curl -H "smsc: uk_gateway" \
https://api.example.com:8443/api/messages
Get pending messages including unrouted messages (backward compatible):
curl -H "smsc: uk_gateway" \
-H "include-unrouted: true" \
https://api.example.com:8443/api/messages
Get all delivered messages:
curl "https://api.example.com:8443/api/messages?status=delivered&limit=50"
Get Single Message
Retrieve details for a specific message.
Request:
GET /api/messages/:id
Response (200 OK):
{
"data": {
"id": 12345,
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_body": "Hello World",
"source_smsc": "api_client",
"dest_smsc": "uk_gateway",
"source_imsi": null,
"dest_imsi": null,
"message_parts": 1,
"message_part_number": 1,
"tp_data_coding_scheme": "00",
"tp_user_data_header": null,
"status": "queued",
"send_time": "2025-10-30T12:00:00Z",
"deliver_time": null,
"expires": "2025-10-31T12:00:00Z",
"deadletter": false,
"delivery_attempts": 0,
"deliver_after": "2025-10-30T12:00:00Z",
"raw_data_flag": false,
"raw_sip_flag": false,
"raw_pdu": null,
"inserted_at": "2025-10-30T12:00:00Z",
"updated_at": "2025-10-30T12:00:00Z"
}
}
Example:
curl https://api.example.com:8443/api/messages/12345
Submit Message (Synchronous)
Submit a message and receive the message ID immediately.
Request:
POST /api/messages
Content-Type: application/json
Body:
{
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_body": "Hello World",
"source_smsc": "api_client"
}
Optional Fields:
dest_smsc- Override routing decisionsend_time- Schedule for future delivery (ISO 8601)message_parts- Total parts for multi-part messagemessage_part_number- Part number (1-indexed)tp_data_coding_scheme- SMS DCS (default: "00")source_imsi- Source subscriber IMSIdest_imsi- Destination subscriber IMSI
Response (201 Created):
{
"data": {
"id": 12345,
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_body": "Hello World",
"source_smsc": "api_client",
"dest_smsc": "uk_gateway",
"status": "queued",
"send_time": "2025-10-30T12:00:00Z",
"inserted_at": "2025-10-30T12:00:00Z"
}
}
Example:
curl -X POST https://api.example.com:8443/api/messages \
-H "Content-Type: application/json" \
-d '{
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_body": "Hello World",
"source_smsc": "api_client"
}'
Performance: ~70 messages/second, 14ms average response time
Use When:
- Need message ID immediately
- Processing messages/second
- Require immediate confirmation
Submit Message (Asynchronous)
Submit a message with high throughput (batch processing).
Request:
POST /api/messages/create_async
Content-Type: application/json
Body: Same as synchronous endpoint
Response (202 Accepted):
{
"data": {
"status": "accepted",
"message": "Message queued for processing"
}
}
Example:
curl -X POST https://api.example.com:8443/api/messages/create_async \
-H "Content-Type: application/json" \
-d '{
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"message_body": "Bulk notification message",
"source_smsc": "bulk_api"
}'
Performance: ~4,650 messages/second, 0.22ms average response time
Latency: Message appears in database within 100ms (configurable)
Use When:
- High-volume bulk messaging ( > 100 msg/sec)
- Don't need message ID in API response
- Throughput more important than instant confirmation
Update Message
Partially update message fields.
Request:
PATCH /api/messages/:id
Content-Type: application/json
Body:
{
"dest_smsc": "alternate_gateway",
"deliver_after": "2025-10-30T14:00:00Z"
}
Updatable Fields:
dest_smsc- Change destinationdeliver_after- Delay deliverymessage_body- Update message textstatus- Change status
Response (200 OK):
{
"data": {
"id": 12345,
"dest_smsc": "alternate_gateway",
"deliver_after": "2025-10-30T14:00:00Z",
...
}
}
Example:
curl -X PATCH https://api.example.com:8443/api/messages/12345 \
-H "Content-Type: application/json" \
-d '{
"dest_smsc": "backup_gateway"
}'
Mark Message Delivered
Mark a message as successfully delivered.
Request:
POST /api/messages/:id/mark_delivered
Content-Type: application/json
Body:
{
"dest_smsc": "uk_gateway"
}
Response (200 OK):
{
"data": {
"id": 12345,
"status": "delivered",
"deliver_time": "2025-10-30T12:05:30Z",
"dest_smsc": "uk_gateway",
...
}
}
Example:
curl -X POST https://api.example.com:8443/api/messages/12345/mark_delivered \
-H "Content-Type: application/json" \
-d '{
"dest_smsc": "uk_gateway"
}'
Use Case: Called by frontend systems after successful delivery
Increment Delivery Attempt
Record a failed delivery: increments the attempt counter, moves the message to
backoff, and schedules the next retry.
Request:
PUT /api/messages/:id
Response (200 OK) — the updated message:
{
"id": 12345,
"status": "backoff",
"delivery_attempts": 2,
"deliver_after": "2025-10-30T12:08:00Z"
}
Backoff: exponential, capped at 30 minutes, and never scheduled past the
message's expires:
deliver_after = min(now + min(2^attempts, 30) minutes, expires)
The message stays in backoff until deliver_after passes, then becomes
eligible again. It keeps retrying every ≤30 minutes until expires is reached,
after which it is no longer served (failed deliveries are not dead-lettered).
Example:
curl -X PUT https://api.example.com:8443/api/messages/12345
Use Case: Called by frontend after delivery failure to schedule retry
Delete Message
Remove message from queue.
Request:
DELETE /api/messages/:id
Response (204 No Content)
Example:
curl -X DELETE https://api.example.com:8443/api/messages/12345
Warning: Deleting messages removes them permanently. Use with caution.
Raw SMS PDU API
Submit SMS messages as raw PDU (Protocol Data Unit) for maximum compatibility with legacy systems.
Submit Raw SMS (Synchronous)
Request:
POST /api/messages_raw
Content-Type: application/json
Body:
{
"pdu": "0001000B916407007009F0000004D4F29C0E",
"source_smsc": "legacy_system"
}
PDU Format: Hex-encoded SMS TPDU (Transport Protocol Data Unit)
Response (201 Created):
{
"data": {
"id": 12346,
"source_msisdn": "+447700900000",
"destination_msisdn": "+447700900000",
"message_body": "Test",
"source_smsc": "legacy_system",
"raw_pdu": "0001000B916407007009F0000004D4F29C0E",
...
}
}
Example:
curl -X POST https://api.example.com:8443/api/messages_raw \
-H "Content-Type: application/json" \
-d '{
"pdu": "0001000B916407007009F0000004D4F29C0E",
"source_smsc": "legacy_system"
}'
Submit Raw SMS (Asynchronous)
Request:
POST /api/messages_raw/async
Content-Type: application/json
Body: Same as synchronous
Response (202 Accepted):
{
"data": {
"status": "accepted",
"message": "PDU queued for processing"
}
}
Example:
curl -X POST https://api.example.com:8443/api/messages_raw/async \
-H "Content-Type: application/json" \
-d '{
"pdu": "0001000B916407007009F0000004D4F29C0E",
"source_smsc": "legacy_gateway"
}'
PDU Handling
The system automatically:
- Decodes PDU using SMS standards (3GPP TS 23.040)
- Extracts phone numbers, message text, DCS
- Detects delivery reports (CP-ACK, RP-ACK, etc.)
- Performs IMSI to MSISDN lookup if needed
- Applies routing rules
- Stores original PDU for reference
Delivery Report Detection:
- CP-ACK, CP-ERROR - Connection Protocol acknowledgments
- RP-ACK, RP-ERROR, RP-SMMA - Relay Protocol responses
- Delivery reports are logged but not stored as messages
Location Management API
Manage subscriber location information for mobile-terminated message delivery.
List Locations
Request:
GET /api/locations
Response (200 OK):
{
"data": [
{
"id": 1,
"msisdn": "+15551234567",
"imsi": "001001000000001",
"location": "msc1.region1.example.com",
"ran_location": "cell_tower_12345",
"imei": "123456789012345",
"ims_capable": true,
"csfb": false,
"registered": true,
"expires": "2025-10-30T13:00:00Z",
"user_agent": "Samsung Galaxy",
"inserted_at": "2025-10-30T12:00:00Z",
"updated_at": "2025-10-30T12:00:00Z"
}
]
}
Example:
curl https://api.example.com:8443/api/locations
Get Location
Request:
GET /api/locations/:id
Response (200 OK):
{
"data": {
"id": 1,
"msisdn": "+15551234567",
"imsi": "001001000000001",
...
}
}
Example:
curl https://api.example.com:8443/api/locations/1
Create/Update Location
Creates new location or updates existing based on IMSI (unique identifier).
Request:
POST /api/locations
Content-Type: application/json
Body:
{
"msisdn": "+15551234567",
"imsi": "001001000000001",
"location": "msc1.region1.example.com",
"ran_location": "cell_tower_12345",
"imei": "123456789012345",
"ims_capable": true,
"csfb": false,
"registered": true,
"expires": "2025-10-30T13:00:00Z",
"user_agent": "Samsung Galaxy"
}
Required Fields:
imsi- Unique subscriber identifiermsisdn- Phone number
Optional Fields:
location- MSC/VLR addressran_location- Cell tower/sector IDimei- Device identifierims_capable- IMS VoLTE capabilitycsfb- Circuit-switched fallback flagregistered- Currently registeredexpires- Registration expiryuser_agent- Device model/info
Response (201 Created or 200 OK):
{
"data": {
"id": 1,
"msisdn": "+15551234567",
...
}
}
Example:
curl -X POST https://api.example.com:8443/api/locations \
-H "Content-Type: application/json" \
-d '{
"msisdn": "+15551234567",
"imsi": "001001000000001",
"location": "msc1.region1.example.com",
"ims_capable": true,
"registered": true
}'
Use Case: Called by mobility management systems (HSS, MME, etc.) when subscriber registers
Update Location
Request:
PATCH /api/locations/:id
Content-Type: application/json
Body: Partial update with any location fields
Response (200 OK):
{
"data": {
"id": 1,
...
}
}
Example:
curl -X PATCH https://api.example.com:8443/api/locations/1 \
-H "Content-Type: application/json" \
-d '{
"location": "msc2.region2.example.com",
"ran_location": "cell_tower_67890"
}'
Delete Location
Request:
DELETE /api/locations/:id
Response (204 No Content)
Example:
curl -X DELETE https://api.example.com:8443/api/locations/1
Use Case: Called when subscriber de-registers or times out
Frontend Registration API
Track and manage frontend SMSC connections.
List All Frontends
Request:
GET /api/frontends
Response (200 OK):
{
"data": [
{
"id": 1,
"frontend_name": "uk_gateway_1",
"frontend_type": "smpp",
"ip_address": "10.0.1.50",
"hostname": "gateway1.uk.example.com",
"uptime_seconds": 86400,
"configuration": {
"max_throughput": 1000,
"bind_type": "transceiver"
},
"status": "active",
"expires_at": "2025-10-30T12:02:00Z",
"last_seen_at": "2025-10-30T12:00:30Z",
"inserted_at": "2025-10-29T12:00:00Z",
"updated_at": "2025-10-30T12:00:30Z"
}
]
}
Example:
curl https://api.example.com:8443/api/frontends
List Active Frontends Only
Request:
GET /api/frontends/active
Response (200 OK): Same format, only active frontends
Example:
curl https://api.example.com:8443/api/frontends/active
Use Case: Get list of available destinations for routing
Get Frontend Statistics
Request:
GET /api/frontends/stats
Response (200 OK):
{
"data": {
"active_count": 5,
"expired_count": 2,
"unique_frontends": 7,
"total_registrations": 1523
}
}
Example:
curl https://api.example.com:8443/api/frontends/stats
Get Frontend History
Request:
GET /api/frontends/history/:name
Response (200 OK):
{
"data": [
{
"id": 1,
"frontend_name": "uk_gateway_1",
"status": "active",
"inserted_at": "2025-10-30T12:00:00Z",
...
},
{
"id": 2,
"frontend_name": "uk_gateway_1",
"status": "expired",
"inserted_at": "2025-10-29T12:00:00Z",
...
}
]
}
Example:
curl https://api.example.com:8443/api/frontends/history/uk_gateway_1
Register Frontend
Register or update frontend connection.
Request:
POST /api/frontends/register
Content-Type: application/json
Body:
{
"frontend_name": "uk_gateway_1",
"frontend_type": "smpp",
"ip_address": "10.0.1.50",
"hostname": "gateway1.uk.example.com",
"uptime_seconds": 86400,
"configuration": {
"max_throughput": 1000,
"bind_type": "transceiver",
"system_id": "gateway1"
}
}
Required Fields:
frontend_name- Unique identifier for frontendfrontend_type- Type:smpp,sip,http, etc.
Optional Fields:
ip_address- Frontend IPhostname- Frontend hostnameuptime_seconds- Uptime since startconfiguration- Custom config object
Response (201 Created):
{
"data": {
"id": 1,
"frontend_name": "uk_gateway_1",
"status": "active",
"expires_at": "2025-10-30T12:01:30Z",
...
}
}
Example:
curl -X POST https://api.example.com:8443/api/frontends/register \
-H "Content-Type: application/json" \
-d '{
"frontend_name": "uk_gateway_1",
"frontend_type": "smpp",
"ip_address": "10.0.1.50",
"hostname": "gateway1.uk.example.com"
}'
Registration Timeout: 90 seconds (frontends must re-register every 60-90 seconds)
Use Case: Called periodically by frontend systems to maintain active status
Campaigns API
Bulk messaging: upload a named recipient list, then run a rate-limited campaign against it. See the Bulk Messaging / Campaigns guide for concepts (audience filter, drip rate, lifecycle, statistics).
Recipient Lists
Create a List
Request:
POST /api/campaign_lists
Content-Type: application/json
Each recipient may carry up to four template variables (var1..var4).
Body — supply recipients as a JSON array, a raw CSV string, or both. JSON
recipients may be plain MSISDN strings or objects with var1..var4:
{
"name": "VIP customers",
"description": "High value subscribers",
"recipients": [
{ "msisdn": "12025550101", "var1": "Alice", "var2": "Gold" },
"12025550102"
]
}
For CSV, a header row naming an msisdn / destination_msisdn / number /
phone column selects the MSISDN column (otherwise the first column is used);
the remaining columns become var1..var4 in column order:
{ "name": "Imported", "csv": "msisdn,first,plan\n12025550101,Alice,Gold\n12025550102,Bob,Silver\n" }
Response (201 Created):
{ "id": 1, "name": "VIP customers", "recipient_count": 2 }
List / Get / Append / Delete Lists
GET /api/campaign_lists # all lists
GET /api/campaign_lists/:id # one list, includes "recipients": [{msisdn, variables}, ...]
PATCH /api/campaign_lists/:id # append recipients ({"recipients": [...]} and/or {"csv": "..."})
DELETE /api/campaign_lists/:id # delete the list and its recipients
Campaigns
Create a Campaign
Request:
POST /api/campaigns
Content-Type: application/json
Body:
{
"name": "Maintenance notice",
"message": "Planned maintenance tonight 02:00-03:00.",
"source_msisdn": "12345",
"source_smsc": "IMS_SMSC",
"list_id": 1,
"audience": "active_only",
"drip_tps": 50
}
Fields:
name,message,source_msisdn,source_smsc— requiredlist_id— recipient list. Omit to target ALL currently active (registered) subscribers.audience—active_only(default) orall. Ignored whenlist_idis omitted.drip_tps— messages submitted into the queue per second (default from config).validity_hours— message validity period in hours; sets each message'sexpires(default from config).deliver_after— optional ISO8601 time to hold messages until before delivery (scheduled send).
Response (201 Created): the campaign in draft status, including a live
stats block.
Control a Campaign (start / pause / resume / cancel)
Request:
POST /api/campaigns/control
Content-Type: application/json
Body:
{ "campaign_id": 7, "action": "start" }
action is one of start, pause, resume, cancel. Returns the updated
campaign (200), 404 if not found, or 422 if the action is invalid for the
current state.
List / Get Campaigns
GET /api/campaigns # all campaigns (newest first)
GET /api/campaigns/:id # one campaign, including live stats
Response (GET /api/campaigns/:id):
{
"id": 7,
"name": "Maintenance notice",
"list_id": 1,
"audience": "active_only",
"status": "running",
"drip_tps": 50,
"total_targets": 1000,
"stats": {
"total": 1000, "pending": 600, "queued": 300,
"delivered": 90, "failed": 10, "skipped_inactive": 0,
"dispatched": 400, "progress_percent": 40, "delivery_percent": 22
}
}
Delete (Stop) a Campaign
DELETE /api/campaigns/:id
Deleting stops the campaign (cancels delivery) but keeps the record so its history and statistics remain visible; it returns the cancelled campaign (200). The record is purged automatically once it ages past the retention TTL.
Per-Recipient Results
GET /api/campaign_targets/:id # :id is the campaign ID
GET /api/campaign_targets/:id?state=failed # filter by target state
Returns one entry per recipient with its state
(pending / queued / delivered / failed / skipped_inactive), the
submitted message_ids, and part counters.
Event Logging API
Track message lifecycle events.
Get Message Events
Request:
GET /api/events/:message_id
Response (200 OK):
{
"data": [
{
"event_epoch": 1698672000,
"name": "message_inserted",
"description": "Message inserted into queue",
"event_source": "node1@server.example.com"
},
{
"event_epoch": 1698672001,
"name": "message_routed",
"description": "Routed to uk_gateway via route_id=42",
"event_source": "node1@server.example.com"
},
{
"event_epoch": 1698672005,
"name": "message_delivered",
"description": "Successfully delivered",
"event_source": "node2@server.example.com"
}
]
}
Example:
curl https://api.example.com:8443/api/events/12345
Event Types:
message_inserted- Message createdmessage_routed- Routing decision mademessage_delivered- Successful deliverymessage_failed- Delivery failedmessage_dropped- Dropped by routeauto_reply_sent- Auto-reply triggerednumber_translated- Number transformation appliedrouting_failed- No route foundcharging_failed- Charging error
Record Event
Request:
POST /api/events
Content-Type: application/json
Body:
{
"message_id": 12345,
"name": "custom_event",
"description": "Custom event description",
"event_source": "external_system"
}
Response (201 Created):
{
"data": {
"message_id": 12345,
"name": "custom_event",
"description": "Custom event description",
"event_source": "external_system",
"event_epoch": 1698672010
}
}
Example:
curl -X POST https://api.example.com:8443/api/events \
-H "Content-Type: application/json" \
-d '{
"message_id": 12345,
"name": "external_delivery_confirmed",
"description": "Confirmed by downstream system"
}'
Event Retention: 7 days (configurable)
MMS Message API
Manage Multimedia Messaging Service (MMS) messages.
List MMS Messages
Request:
GET /api/mms_messages
Response (200 OK): Similar to SMS messages with additional MMS fields
Create MMS Message
Request:
POST /api/mms_messages
Content-Type: application/json
Body:
{
"source_msisdn": "+15551234567",
"destination_msisdn": "+447700900000",
"subject": "Photo",
"content_type": "image/jpeg",
"content_location": "https://cdn.example.com/media/12345.jpg",
"message_size": 524288
}
Response (201 Created): Full MMS message object
SS7 Event API
Track SS7 signaling events.
List SS7 Events
Request:
GET /api/ss7_events
Response (200 OK):
{
"data": [
{
"id": 1,
"event_type": "MAP_UPDATE_LOCATION",
"imsi": "001001000000001",
"msisdn": "+15551234567",
"timestamp": "2025-10-30T12:00:00Z",
...
}
]
}
Create SS7 Event
Request:
POST /api/ss7_events
Content-Type: application/json
Body:
{
"event_type": "MAP_UPDATE_LOCATION",
"imsi": "001001000000001",
"msisdn": "+15551234567"
}
Response (201 Created): Full event object
Error Codes
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 202 | Accepted | Request accepted for processing |
| 204 | No Content | Successful deletion |
| 400 | Bad Request | Invalid request format |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 422 | Unprocessable Entity | Validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
| 503 | Service Unavailable | Temporarily unavailable |
Error Response Format
{
"errors": {
"detail": "Validation failed: destination_msisdn is required"
}
}
Common Error Messages
| Error | Cause | Solution |
|---|---|---|
| "destination_msisdn is required" | Missing required field | Include destination_msisdn in request |
| "Invalid phone number format" | Malformed number | Use E.164 format: +15551234567 |
| "Message too long" | Exceeds size limit | Split into multiple parts |
| "No route found" | Routing failed | Check routing configuration |
| "Charging failed" | OCS error | Verify charging system connectivity |
| "Message not found" | Invalid message ID | Verify ID exists |
| "Frontend not registered" | Unknown SMSC | Register frontend first |
Rate Limiting
Default Limits
| Endpoint | Limit | Window |
|---|---|---|
| POST /api/messages | 100 req/sec | Per IP |
| POST /api/messages/create_async | 1000 req/sec | Per IP |
| POST /api/messages_raw | 100 req/sec | Per IP |
| GET /api/* | 1000 req/sec | Per IP |
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1698672060
Rate Limit Exceeded
Response (429 Too Many Requests):
{
"errors": {
"detail": "Rate limit exceeded. Retry after 5 seconds."
}
}
Best Practices
Message Submission
- Use Async for Bulk: Use
/create_asyncfor > 100 msg/sec - Include source_smsc: Always identify your system
- Validate Numbers: Use E.164 format (+country code)
- Handle Errors: Implement retry logic for 5xx errors
- Check Routing: Test routes before bulk submission
Frontend Integration
- Register Regularly: Re-register every 60 seconds
- Poll for Messages: Query with
smscheader for your messages - Use include-unrouted Wisely: By default, only messages with explicit routing or location registration are returned. Set
include-unrouted: trueonly if you need backward compatible behavior to receive all unrouted messages - Mark Delivered: Always call mark_delivered after success
- Increment on Failure: Use PUT endpoint for retry logic
- Monitor Events: Check event log for delivery issues
Performance
- Connection Pooling: Reuse HTTP connections
- Batch Requests: Group multiple messages per request
- Parallel Processing: Make concurrent API calls
- Monitor Metrics: Watch Prometheus for bottlenecks
- Set Timeouts: Use 30-second timeout for API calls
Security
- Use TLS: Always use HTTPS in production
- Validate Certificates: Don't skip certificate validation
- Rotate API Keys: Change keys regularly
- IP Whitelist: Restrict to known sources
- Log API Activity: Monitor for suspicious patterns
Error Handling
- Retry 5xx Errors: Server errors are usually temporary
- Don't Retry 4xx: Client errors need code fixes
- Exponential Backoff: Wait longer between retries
- Circuit Breaker: Stop after repeated failures
- Alert on Patterns: Monitor error rates
Example Integration (Python)
import requests
import time
class SMSCClient:
def __init__(self, base_url, api_key=None):
self.base_url = base_url
self.session = requests.Session()
if api_key:
self.session.headers.update({"X-API-Key": api_key})
def submit_message(self, from_num, to_num, text, async_mode=False):
endpoint = "/messages/create_async" if async_mode else "/messages"
url = f"{self.base_url}{endpoint}"
payload = {
"source_msisdn": from_num,
"destination_msisdn": to_num,
"message_body": text,
"source_smsc": "python_client"
}
try:
response = self.session.post(url, json=payload, timeout=30)
response.raise_for_status()
return response.json()["data"]
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
return None
def get_pending_messages(self, smsc_name, include_unrouted=False):
url = f"{self.base_url}/messages"
headers = {"smsc": smsc_name}
# Include unrouted messages if requested (backward compatible mode)
if include_unrouted:
headers["include-unrouted"] = "true"
try:
response = self.session.get(url, headers=headers, timeout=30)
response.raise_for_status()
return response.json()["data"]
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
return []
def mark_delivered(self, message_id, smsc_name):
url = f"{self.base_url}/messages/{message_id}/mark_delivered"
payload = {"dest_smsc": smsc_name}
try:
response = self.session.post(url, json=payload, timeout=30)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
return False
# Usage
client = SMSCClient("https://api.example.com:8443/api", api_key="your_key")
# Submit single message
result = client.submit_message("+15551234567", "+447700900000", "Hello")
print(f"Message ID: {result['id']}")
# Submit bulk messages (async)
for i in range(1000):
client.submit_message("+15551234567", f"+44770090{i:04d}", f"Bulk {i}", async_mode=True)
# Frontend polling loop
while True:
# Get messages with explicit routing or location registration
messages = client.get_pending_messages("my_gateway")
# Or use include_unrouted=True for backward compatible behavior
# messages = client.get_pending_messages("my_gateway", include_unrouted=True)
for msg in messages:
# Deliver message via your protocol
success = deliver_via_smpp(msg)
if success:
client.mark_delivered(msg["id"], "my_gateway")
else:
# Increment for retry
requests.put(f"{client.base_url}/messages/{msg['id']}")
time.sleep(5) # Poll every 5 seconds
API Changelog
Version 1 (Current)
- Initial release
- Message queue CRUD
- Raw PDU submission
- Location management
- Frontend registration
- Event logging
Planned Features
- Batch message submission (single request, multiple messages)
- Message templates
- Scheduled delivery API
- Real-time webhooks for events
- GraphQL API endpoint
- OAuth2 authentication
For questions or issues with the API, check the Troubleshooting Guide or contact support.