Base URL
https://your-domain.com/api/v1
All endpoints are prefixed with /api/v1. HTTPS only. All request and response bodies are JSON.
Authentication
Two auth methods are supported — use either in the Authorization header:
Authorization: Bearer <accessToken>From POST /auth/login. Expires 15 min. Rotate via POST /auth/refresh.
Authorization: ApiKey <key>Generated in the dashboard. Shown only once on creation. Never expires unless revoked.
Quick start
Register → get an API key → send your first SMS in under 5 minutes:
# 1. Get an access token
curl -X POST https://your-domain.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@org.com","password":"yourpassword"}'
# Response:
# { "accessToken": "eyJ...", "refreshToken": "..." }
# 2. Send an SMS
curl -X POST https://your-domain.com/api/v1/sms/send \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{"to":"+256700000000","message":"Hello from MARIPA_E-SYNC!"}'Send SMS
/sms/sendSend a single SMS. Cost is deducted from your wallet on dispatch.
{
"status": "SENT",
"messageId": "msg_01j9k3xhf7abc",
"to": "+256700000000",
"cost": "$0.035",
"segments": 1,
"sentAt": "2026-06-07T08:12:03Z"
}Bulk send
/sms/bulkSend the same message to multiple recipients. Each number gets an individual delivery record.
# Request
{
"to": ["+256700000001", "+256700000002", "+254712345678"],
"message": "Your promo code is JUNE20. Valid today only.",
"senderId": "MARIPA"
}
# Response
{
"queued": 3,
"totalCost": "$0.105",
"batchId": "batch_abc123",
"results": [
{ "to": "+256700000001", "status": "SENT", "messageId": "msg_01..." },
{ "to": "+256700000002", "status": "SENT", "messageId": "msg_02..." },
{ "to": "+254712345678", "status": "SENT", "messageId": "msg_03..." }
]
}OTP
/sms/otpSend a one-time password. The platform generates a 6-digit code and sends it. You verify the code via /sms/otp/verify.
# Send OTP
POST /sms/otp
{ "to": "+256700000000", "purpose": "login" }
# Response
{ "otpId": "otp_xyz789", "expiresIn": 300 }
# Verify OTP
POST /sms/otp/verify
{ "otpId": "otp_xyz789", "code": "847291" }
# Response
{ "valid": true }Campaigns
# Create a campaign
POST /campaigns
{
"name": "June Promotion",
"message": "Get 20% off today! Use JUNE20",
"groupIds": ["grp_abc123"]
}
# → { "id": "cmp_...", "status": "DRAFT" }
# Send it
POST /campaigns/{id}/send
# Track delivery
GET /campaigns/{id}
# → { "delivered": 4821, "failed": 12, "pending": 0 }Errors
All errors return { "error": "..." } with a standard HTTP status code.
Rate limits
Applied per tenant. Limits reset every 60 seconds. Exceeded requests return 429.
Webhooks — Delivery report
Configure a delivery report URL in your tenant settings. We POST a JSON payload when a message status changes.
# Payload sent to your webhook URL
{
"event": "delivery.report",
"messageId": "msg_01j9k3xhf7abc",
"to": "+256700000000",
"status": "DELIVERED",
"timestamp": "2026-06-07T08:12:04Z",
"latencyMs": 487
}
# Possible statuses: SENT DELIVERED FAILED EXPIREDWebhook signature
Every webhook request includes X-E-Sync-Signature — an HMAC-SHA256 of the raw body, signed with your webhook secret.
// Node.js verification
const crypto = require('crypto');
function isValidSignature(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Acceptable use policy
Data retention
90 daysContent, recipient, status, cost.90 daysPer-message timestamps and status changes.30 daysPath, status code, latency — no body logging.1 yearAuth events, settings changes, wallet transactions.Until deletedRetained until you delete them.