Developers
API reference
Send OTPs, alerts and campaigns from your own software. JSON in, JSON out, bearer-key authentication.
Base URL
https://sms.allotropicltd.com/api/public/v1Authentication
Create a key on the Developers page and send it as a bearer token on every request. Keys are shown once; store them securely and revoke them if exposed.
Authorization: Bearer alt_live_xxxxxxxx
Phone numbers
Local numbers default to Tanzania (+255): 0712345678 becomes 255712345678.
Numbers in other countries must be international: 2547…, +44…, 00971…. Invalid and duplicate numbers are returned in rejected and are not charged.
Billing and message parts
1 credit = 1 SMS part. Standard (GSM-7) messages fit 160 characters in one part, or 153 per part when longer. Unicode messages (emoji, non-Latin scripts) fit 70, or 63 per part when longer.
Credits are reserved when a request is accepted. Messages that fail permanently, and cancelled scheduled messages, are refunded automatically.
Sent vs delivered
queued: accepted and waiting to be sent (including scheduled and retrying messages).
sent: handed to the mobile network. This is not proof the handset received it.
delivered: the network confirmed delivery to the handset. Delivery confirmations are being rolled out; until then most messages will finish as sent.
failed: could not be sent after retries; credits refunded. cancelled: a scheduled message cancelled before sending.
Scheduling and retries
Pass schedule_at (ISO 8601, UTC recommended). Temporary failures retry automatically with growing delays (2, 4, 8, 16 minutes) up to 5 attempts.
Idempotency
Send an Idempotency-Key header (any unique string) on send calls. Repeating a request with the same key returns the original campaign with duplicate: true and is not charged again.
Rate limits and pagination
Each API key may make 120 requests per minute; beyond that you receive HTTP 429. Lists use page and per_page (max 500) and return meta.total.
Send SMS
Send the same message to one or many numbers (up to 10,000). to accepts a string, a comma-separated string or an array.
sender_id(string, required, max 13): an approved sender ID on your accountto(string | string[], required): local Tanzanian (0712345678) or international (255712345678 / +255712345678) numbersmessage(string, required, max 1600 characters)schedule_at(ISO 8601, optional): send later; must be at least 30 seconds in the futurereference(string, optional, max 120): your campaign label
{
"sender_id": "MYBRAND",
"to": ["255712345678", "0754000000"],
"message": "Your verification code is 4821",
"schedule_at": "2026-12-01T08:00:00Z",
"reference": "December promo"
}{
"success": true,
"data": {
"campaign_id": "6f1c2a8e-…",
"status": "scheduled",
"accepted": 2,
"rejected": [],
"credits_used": 2,
"balance": 998,
"duplicate": false
}
}curl -X POST https://sms.allotropicltd.com/api/public/v1/sms/send \
-H "Authorization: Bearer alt_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{"sender_id":"MYBRAND","to":"255712345678","message":"Your code is 4821"}'Send personalised bulk
Different text per recipient in one request (up to 10,000 items).
sender_id(string, required)messages(array, required): items of{ "to": string, "message": string }schedule_at,reference: as for Send SMS
{
"sender_id": "MYBRAND",
"messages": [
{ "to": "255712345678", "message": "Hi Neema, your order has shipped" },
{ "to": "255754000000", "message": "Hi Juma, your order has shipped" }
]
}{ "success": true, "data": { "campaign_id": "…", "status": "completed", "accepted": 2, "rejected": [], "credits_used": 2, "balance": 996, "duplicate": false } }Message or campaign status
Pass a message ID or a campaign ID returned by a send call. Campaigns include up to 1,000 messages.
{ "success": true, "data": { "id": "…", "campaign_id": "…", "to": "255712345678", "sender_id": "MYBRAND", "message": "…", "parts": 1, "encoding": "GSM7", "status": "sent", "error": null, "created_at": "…", "sent_at": "…", "delivered_at": null } }Reports
Paginated message list, newest first.
status: queued | sent | delivered | failed | cancelledto: phone number contains digitssender_id,campaign_idfrom,to_date: ISO datespage(default 1),per_page(default 100, max 500)
{ "success": true, "data": [ … ], "meta": { "page": 1, "per_page": 100, "total": 532 } }Balance
Remaining SMS credits.
{ "success": true, "data": { "credits": 998 } }Sender IDs
Active sender IDs approved for your account.
{ "success": true, "data": [ { "sender_id": "MYBRAND", "default": true } ] }Webhooks
Set an https URL on the Developers page. We POST final status changes (sent, failed) in batches. Respond with any 2xx within 5 seconds; delivery is best effort and not retried.
POST https://your-app.example.com/sms-status
Content-Type: application/json
User-Agent: AllotropicSMS-Webhook/1.0
{ "event": "message.status", "data": [ { "id": "…", "to": "255712345678", "status": "sent", "error": null } ] }Errors
{ "success": false, "error": { "code": "INSUFFICIENT_CREDITS", "message": "…" } }| 400 | INVALID_JSON | Body is not valid JSON |
| 401 | UNAUTHORIZED | Missing, invalid or revoked API key |
| 402 | INSUFFICIENT_CREDITS | Not enough credits for this request |
| 403 | INVALID_SENDER_ID | Sender ID is not approved for your account |
| 403 | ACCOUNT_SUSPENDED | Account is suspended |
| 404 | NOT_FOUND | Message or campaign not found |
| 422 | VALIDATION_ERROR | Request body or query is invalid |
| 422 | NO_VALID_RECIPIENTS | None of the numbers are valid |
| 429 | RATE_LIMITED | More than 120 requests per minute per key |
| 500 | INTERNAL | Unexpected error: retry with the same Idempotency-Key |