Kalert API

Kalert Messaging API

v1.0Base URL: https://springback.kalert.netREST / JSONAsync via Kafka

The Kalert Messaging API lets you send messages across multiple channels — SMS, Email, and WhatsApp — through a single unified endpoint. Messages are dispatched asynchronously via Kafka, giving you fast acknowledgement and reliable delivery. All sent messages are logged to MongoDB for audit and reporting.

All requests must include a valid X-API-Key header. The API key determines the authenticated user, controls rate limiting, and is used to validate sender permissions.

How it works

When you call POST /api/schedule/send, the API validates your key, deducts credits, queues the message in Kafka, and returns a 202 QUEUED response immediately. The Kafka consumer then picks up the message, dispatches it through the appropriate channel, and logs the outcome (SENT or FAILED) to MongoDB. If dispatch fails, credits are automatically refunded.

Authentication

Every request must include your API key as a request header. Keys are managed in the apikeys table and must have a status of active or enabled to be accepted.

Header

X-API-Key: your-api-key-here

Key statuses

StatusBehaviour
active / enabledAccepted — requests proceed normally
disabledRejected with 401
Missing keyRejected with 401 Invalid API key
Never expose your API key in client-side code or public repositories. Treat it like a password.

Sender ID Endpoints

Use these endpoints to request sender names, check approval status, and list sender records tied to your API key. Every sender request is created with a pending status and must be approved before it can be used for SMS delivery.

Request a Sender ID

POST/api/senders/request

Creates a new sender request for the authenticated user. The API saves the sender with pending status immediately.

Required header

X-API-Key: your-api-key

Request body

{
  "senderName": "MySender",
  "purpose": "For transaction alerts"
}
Behavior: status is set to pending on creation.

Check Sender Status

GET/api/senders/{senderName}/status

Returns the latest approval status for a specific sender name owned by the API key's user. This endpoint refreshes and returns the current senders.status value.

Required header

X-API-Key: your-api-key
Behavior: updates senders.status immediately and returns the updated status.

List Sender Records

GET/api/senders

Lists all sender records that belong to the authenticated API key user, including their current status and metadata.

Required header

X-API-Key: your-api-key
Behavior: returns all sender records scoped to that API key's user account.

Errors & Response Codes

All error responses follow a consistent JSON structure:

Error response body

{
  "status":    401,
  "message":   "Invalid API key",
  "timestamp": "2026-03-27T10:00:00Z"
}
CodeMeaningCommon cause
202AcceptedMessage queued successfully
200OKLog query returned successfully
400Bad requestMissing or invalid request body fields
401UnauthorizedInvalid, missing, or disabled API key; unapproved sender
402Payment requiredInsufficient credits to dispatch the message
429Too many requestsRate limit of 100 req/min exceeded
500Server errorUnexpected internal error

Rate Limiting

Each API key is limited to 100 requests per minute using a token bucket algorithm. The bucket refills fully every 60 seconds.

When the limit is exceeded you receive a 429 response with a message indicating how many seconds to wait before retrying.

429 Response example

{
  "status":    429,
  "message":   "Rate limit exceeded. Retry after 43s",
  "timestamp": "2026-03-27T10:00:00Z"
}

Credits & Billing

Credits are deducted immediately when the message is queued. If delivery fails, the deducted credits are automatically refunded. The amount depends on channel and message size.

Credit rates by channel

ChannelRateNotes
SMS1 credit per 160-char segmentLong messages are split into segments and billed per segment
WHATSAPP2 credits per messageEach send counts as 2 credits regardless of length
EMAIL1 credit per emailSingle email send is always 1 credit

Credit types (deduction order)

The system deducts from credit pools in the order configured in the creditusage table — typically: expiry balance first, then bonus, then non-expiry.

PoolFieldNotes
Expiry balanceexpirybalanceTime-limited credits, used first
Bonus balancebonusbalancePromotional credits, used second
Non-expiry balancenonexpirybalancePermanent credits, used last
If message delivery fails for any reason, the exact amount and type of credits deducted are automatically refunded to the user's account.
If all credit pools are insufficient, the request returns 402 Payment Required and no message is queued.

Send a Message

Validates the API key, deducts credits, and publishes the message to Kafka. Returns 202 as soon as the message is queued. Actual delivery happens asynchronously.

POST/api/messages/send

Headers

HeaderRequiredDescription
X-API-KeyrequiredYour API key
Content-Typerequiredapplication/json

Request body

FieldTypeDescription
channelstringSMS, EMAIL, or WHATSAPP
recipientstringPhone number (SMS/WhatsApp) or email; use recipients for bulk
recipientsarrayList of recipients for bulk delivery
bodystringMessage content
senderNamestringRequired for SMS — Sender ID, max 11 chars, registered in senders table
subjectstringEmail subject — only when channel is EMAIL
isSchedulebooleanFor /api/schedule/send — enable future delivery
scheduleDatestringWhen isSchedule is true — YYYY-MM-DD HH:MM:SS
recursionstringdaily, weekly, or monthly for recurring schedules

SMS example

The senderName must match an entry in the senders table that belongs to your account and has status approved. Max 11 characters.

Request

POST https://springback.kalert.net/api/messages/send
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel":    "SMS",
  "recipient":  "233592548849",
  "senderName": "Sender ID",
  "body":       "Hello from Kalert API!",
  "isSchedule": false,
  "scheduleDate": ""
}

Response — 202 Accepted

{
  "status":    "QUEUED",
  "message":   "Your message has been queued for delivery",
  "channel":   "SMS",
  "recipient": "233592548849"
}

Email example

Request

POST https://springback.kalert.net/api/messages/send
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel":   "EMAIL",
  "recipient": "user@example.com",
  "subject":   "Your Kalert notification",
  "body":      "This is a test email from the Kalert API.",
  "isSchedule": false,
  "scheduleDate": ""
}

Response — 202 Accepted

{
  "status":    "QUEUED",
  "message":   "Your message has been queued for delivery",
  "channel":   "EMAIL",
  "recipient": "user@example.com"
}

WhatsApp example

Recipients must have previously joined the Twilio WhatsApp sandbox by sending the sandbox join code to +14155238886 before they can receive messages in development mode.

Request

POST https://springback.kalert.net/api/messages/send
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel":   "WHATSAPP",
  "recipient": "+233592548849",
  "body":      "Hello via WhatsApp from Kalert!",
  "isSchedule": false,
  "scheduleDate": ""
}

Response — 202 Accepted

{
  "status":    "QUEUED",
  "message":   "Your message has been queued for delivery",
  "channel":   "WHATSAPP",
  "recipient": "+233592548849"
}

Error scenarios

401 — Invalid / missing API key

{ "status": 401, "message": "Invalid API key", "timestamp": "..." }

401 — API key disabled

{ "status": 401, "message": "API key is disabled", "timestamp": "..." }

401 — Unapproved or unknown sender (SMS)

{ "status": 401, "message": "Sender 'MySender' not found, not owned by this user, or not approved", "timestamp": "..." }

402 — Insufficient credits

{ "status": 402, "message": "Insufficient credits. Need 1 units but balance is insufficient.", "timestamp": "..." }

400 — Validation error

{
  "status":    400,
  "message":   "Validation failed",
  "errors": {
    "body":    "Message body is required",
    "channel": "Channel is required"
  }
}

429 — Rate limit exceeded

{ "status": 429, "message": "Rate limit exceeded. Retry after 43s", "timestamp": "..." }

Bulk sending

Direct bulk sending uses /api/messages/send. For scheduled bulk delivery, use /api/schedule/send instead. Provide a top-level channel and a recipients array for bulk delivery.

Request body (example)

Request

POST https://springback.kalert.net/api/messages/send
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel": "SMS",
  "recipients": ["0592548849", "0208894620"],
  "senderName": "Sender ID",
  "body": "From Kalert API!",
  "isSchedule": false,
  "scheduleDate": ""
}

Notes

  • For a single SMS you may use recipient as a string. For bulk SMS provide a top-level recipients array. The server detects which one is present and dispatches accordingly.
  • senderName is validated against your account (must be an approved sender name) and is used as the SMS sender ID (max 11 chars).
  • Credits are deducted per recipient at the time of queuing (1 unit per recipient). If dispatch fails the credits are refunded.
  • This endpoint is for immediate send-only requests. To schedule a message for future delivery, use /api/schedule/send and set isSchedule to true with a valid scheduleDate (in YYYY-MM-DD HH:MM:SS or ISO-8601 format).

Response — 202 Accepted

{
  "accepted": 2,
  "rejected": 0,
  "details": [
    { "recipient": "0241234567", "status": "QUEUED" },
    { "recipient": "0201234567", "status": "QUEUED" }
  ]
}

Scheduled sending (via /api/schedule/send)

Scheduling uses the /api/schedule/send endpoint. Set isSchedule to true and provide an explicit scheduleDate. The request will be accepted and the message stored for delivery at the requested time.

Request (example)

POST https://springback.kalert.net/api/schedule/send
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel": "SMS",
  "recipients": ["0592548849"],
  "senderName": "Sender ID",
  "body": "Scheduled reminder",
  "isSchedule": true,
  "scheduleDate": "2026-04-01 13:30:00",
  "recursion": "daily"
}

Notes

  • Provide scheduleDate in YYYY-MM-DD HH:MM:SS (server-local or UTC depending on server config); ISO-8601 is also accepted if supported.
  • When scheduled, the API returns a scheduling confirmation and a scheduleId you can use to reference or cancel the scheduled item.

Response — 202 Accepted

{
  "scheduleId": "abc123",
  "status": "SCHEDULED",
  "sendAt": "2023-10-30 17:56:00"
}

Update before due

PUT/api/schedule/5
PUT https://springback.kalert.net/api/schedule/5
X-API-Key: your-api-key
Content-Type: application/json

{
  "channel": "SMS",
  "recipients": ["0531907426"],
  "senderName": "Sender ID",
  "body": "Updated message content",
  "isSchedule": true,
  "scheduleDate": "2026-04-02 09:00:00"
}

Cancel

DELETE/api/schedule/5
DELETE https://springback.kalert.net/api/schedule/5
X-API-Key: your-api-key

Get All Message Logs

Request

GET https://springback.kalert.net/api/messages/logs
X-API-Key: your-api-key

Response — 200 OK

[
  {
    "id":           "65f1a2b3c4d5e6f7a8b9c0d1",
    "userId":       3,
    "channel":      "SMS",
    "recipient":    "233592548849",
    "subject":      null,
    "body":         "Hello from Kalert API!",
    "status":       "SENT",
    "sentAt":       "2026-03-27T11:25:38Z",
    "errorMessage": null
  }
]

Get Logs by Channel

Path parameter

ParameterValues
channelSMS EMAIL WHATSAPP (case-insensitive)

Request

GET https://springback.kalert.net/api/messages/logs/channel/SMS
X-API-Key: your-api-key

Response — 200 OK

[
  {
    "id":        "65f1a2b3c4d5e6f7a8b9c0d1",
    "userId":    3,
    "channel":   "SMS",
    "recipient": "233592548849",
    "body":      "Hello from Kalert API!",
    "status":    "SENT",
    "sentAt":    "2026-03-27T11:25:38Z"
  }
]

Get Logs by Status

Path parameter

ParameterValues
statusSENT or FAILED (case-insensitive)

Request — fetch failed messages

GET https://springback.kalert.net/api/messages/logs/status/FAILED
X-API-Key: your-api-key

Response — 200 OK

[
  {
    "id":           "65f1a2b3c4d5e6f7a8b9c0d2",
    "userId":       3,
    "channel":      "SMS",
    "recipient":    "233592548849",
    "body":         "Hello!",
    "status":       "FAILED",
    "sentAt":       "2026-03-27T11:00:00Z",
    "errorMessage": "mNotify SMS error: Insufficient balance"
  }
]

Get Logs by User

Users can only retrieve their own logs. If the userId in the path does not match the user associated with the provided API key, the request returns 403 Forbidden.

Request

GET https://springback.kalert.net/api/messages/logs/user/3
X-API-Key: your-api-key

Response — 200 OK

[
  {
    "id":        "65f1a2b3c4d5e6f7a8b9c0d1",
    "userId":    3,
    "channel":   "EMAIL",
    "recipient": "user@example.com",
    "subject":   "Test",
    "status":    "SENT",
    "sentAt":    "2026-03-27T10:52:46Z"
  }
]

Response — 403 Forbidden (wrong user)

{ "status": 403, "message": "Forbidden" }

Get Logs by Recipient

Request

GET https://springback.kalert.net/api/messages/logs/recipient/233592548849
X-API-Key: your-api-key

Response — 200 OK

[
  {
    "id":        "65f1a2b3c4d5e6f7a8b9c0d3",
    "userId":    3,
    "channel":   "SMS",
    "recipient": "233592548849",
    "body":      "Hello from Kalert API!",
    "status":    "SENT",
    "sentAt":    "2026-03-27T11:25:38Z"
  }
]