API Documentation

Integrate BulkSMS into your application
v1.0 REST JSON
Getting Started

The PulSend API lets you send and schedule SMS messages to Ugandan phone numbers from your own application. You pay for SMS credits and use them via API calls.

Base URL
https://pulsend.wamz.site/api/
Format
JSON — set Content-Type: application/json
Timezone
Africa/Kampala (EAT, UTC+3)
Max Recipients
1,000 per request
Steps to get started
1
2
Top up SMS credits via Payments — go to Payments and pay via Mobile Money
3
Generate your API key from Settings
4
Make your first API call — see Quick Start below
Authentication

Every request must include your API key as a Bearer token in the Authorization header.

# Add this header to every request
Authorization: Bearer your_api_key_here
Never expose your API key in client-side JavaScript or public repositories. Treat it like a password.
Quick Start

Send your first SMS in under a minute.

# Using curl
curl -X POST https://pulsend.wamz.site/api/sms/send/ \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Hello! Your order is ready for pickup.",
    "recipients": ["+256712345678", "0756123456"]
  }'

# Using Python (requests)
import requests

response = requests.post(
    "https://pulsend.wamz.site/api/sms/send/",
    headers={"Authorization": "Bearer your_api_key_here"},
    json={
        "message": "Hello! Your order is ready for pickup.",
        "recipients": ["+256712345678", "0756123456"]
    }
)
print(response.json())
GET /api/account/balance/ Auth required
Check Balance

Returns your current SMS credit balance and the price per SMS.

# Request
GET /api/account/balance/
Authorization: Bearer your_api_key_here

# Response — 200 OK
{
  "success": true,
  "data": {
    "sms_credits": 450,
    "price_per_sms": "50.00",
    "currency": "UGX"
  },
  "error": null
}
POST /api/sms/send/ Auth required
Send SMS

Send an SMS immediately to one or more recipients. Each recipient consumes one SMS credit.

Request Body
FieldTypeRequiredDescription
messagestringYesSMS text, max 160 characters
recipientsarrayYesPhone numbers, max 1,000
# Request
POST /api/sms/send/
Authorization: Bearer your_api_key_here
Content-Type: application/json

{
  "message": "Dear customer, your invoice #1042 of UGX 150,000 is due on May 20. Pay via MTN MoMo 0700123456.",
  "recipients": ["+256712345678", "0756123456", "256700111222"]
}

# Response — 200 OK
{
  "success": true,
  "data": {
    "id": 1,
    "content": "Dear customer, your invoice #1042...",
    "status": "sent",
    "recipient_count": 3,
    "scheduled_time": null,
    "created_at": "2025-05-01T10:00:00Z"
  },
  "error": null
}

# Error — insufficient credits
{
  "success": false,
  "data": null,
  "error": "Insufficient SMS credits. You have 2 but need 3."
}
POST /api/sms/schedule/ Auth required
Schedule SMS

Queue an SMS to be sent automatically at a future date and time. Credits are deducted immediately on scheduling.

Request Body
FieldTypeRequiredDescription
messagestringYesSMS text, max 160 characters
recipientsarrayYesPhone numbers, max 1,000
scheduled_timedatetimeYesISO 8601, must be in the future
# Request
POST /api/sms/schedule/
Authorization: Bearer your_api_key_here
Content-Type: application/json

{
  "message": "Reminder: School fees of UGX 450,000 due tomorrow. Pay via MTN MoMo 0700123456. St. Mary's College.",
  "recipients": ["+256712345678", "0756123456"],
  "scheduled_time": "2025-12-01T08:00:00+03:00"
}

# Response — 201 Created
{
  "success": true,
  "data": {
    "id": 2,
    "status": "pending",
    "recipient_count": 2,
    "scheduled_time": "2025-12-01T08:00:00+03:00",
    "created_at": "2025-11-30T10:00:00Z"
  },
  "error": null
}
Use ISO 8601 format with timezone offset: 2025-12-01T10:00:00+03:00 for Kampala time (EAT).
GET /api/sms/messages/ Auth required
List Messages

Returns all messages sent or scheduled by your API account, ordered by most recent first.

# Request
GET /api/sms/messages/
Authorization: Bearer your_api_key_here

# Response — 200 OK
{
  "success": true,
  "data": [
    { "id": 2, "status": "pending", "recipient_count": 2, "scheduled_time": "2025-12-01T08:00:00Z", ... },
    { "id": 1, "status": "sent", "recipient_count": 3, "scheduled_time": null, ... }
  ],
  "error": null
}
GET /api/sms/messages/<id>/ Auth required
Message Detail

Returns a single message with its full recipient list and individual delivery statuses.

# Request
GET /api/sms/messages/1/
Authorization: Bearer your_api_key_here

# Response — 200 OK
{
  "success": true,
  "data": {
    "id": 1,
    "content": "Dear customer, your invoice #1042...",
    "status": "sent",
    "scheduled_time": null,
    "created_at": "2025-05-01T10:00:00Z",
    "recipients": [
      { "id": 1, "phone_number": "+256712345678", "status": "pending" },
      { "id": 2, "phone_number": "+256756123456", "status": "pending" }
    ]
  },
  "error": null
}
DELETE /api/sms/messages/<id>/ Auth required
Cancel Scheduled Message

Cancels a pending scheduled message and removes it from the queue. Only works on messages with status: pending.

# Request
DELETE /api/sms/messages/2/
Authorization: Bearer your_api_key_here

# Response — 200 OK
{
  "success": true,
  "data": { "detail": "Message 2 cancelled successfully." },
  "error": null
}

# Error — message already sent
{
  "success": false,
  "data": null,
  "error": "Cannot cancel a message with status \"sent\"."
}
Accepted Phone Formats

Numbers are automatically normalized. Invalid numbers are silently skipped. Duplicates are removed.

FormatExampleNotes
Local071234567810 digits starting with 0
Without +25671234567812 digits starting with 256
International+25671234567813 characters starting with +256
Response Format

All responses follow a consistent structure:

{
  "success": true | false,
  "data":    object | array | null,
  "error":   string | object | null
}
FieldDescription
successtrue on success, false on error
dataResponse payload on success, null on error
errorError message or validation details on failure, null on success
Error Codes
CodeMeaningCommon Cause
400Bad RequestMissing fields, invalid data, no valid phone numbers
401UnauthorizedMissing, invalid, or inactive API key
402Payment RequiredInsufficient SMS credits
404Not FoundMessage ID does not exist or belongs to another account
500Server ErrorUnexpected error — contact support
Validation Error Example
{
  "success": false,
  "data": null,
  "error": {
    "message": ["This field is required."],
    "recipients": ["This list may not be empty."]
  }
}
Need help?

Email support@vipulse.ug or WhatsApp us. Include your API key (first 8 characters only) and the request/response details.