Send SMS programmatically, track delivery, and manage contacts — the same REST API that powers the MoSMS dashboard.
Send SMS (and soon WhatsApp) programmatically through MoSMS — a multi-tenant SMS/WhatsApp messaging platform for Tanzania.
https://mosms.co.tz/apiSet the collection variable baseUrl if you ever need to point requests elsewhere.
MoSMS uses Bearer token authentication (Laravel Sanctum personal access tokens) — there is no separate api_key parameter.
token from the response. `` Authorization: Bearer <token> ``
This collection is pre-wired to do this automatically: Login and Register each run a test script that saves the returned token into the collection variable token, and every other request inherits Bearer auth from the collection root using {{token}}. Just run Login once, then everything else works.
Each tenant user has a granular permission set (returned as permissions by Login/Me). Calling an endpoint your token lacks permission for returns 403. Common permissions referenced below: messages.send, bulk_sms.send, group_sms.send, messages, messages.view, messages.check_status, messages.cancel_scheduled, messages.delete, dashboard, contacts*, groups*, templates*, sms_logs, delivery_reports, purchase_sms*, events, events.add, events.view, events.edit, events.delete, events.manage_invitees, events.manage_payments, events.send_sms.
The three Send SMS endpoints (/sms/send, /sms/send-bulk, /sms/send-group/{group}) are throttled to 60 requests/minute per tenant. Exceeding this returns 429 Too Many Requests. No other endpoint is currently rate-limited.
Send numbers in any reasonable local or international format — 0712345678, +255712345678, or 255712345678 all work; MoSMS normalizes to the 255XXXXXXXXX MSISDN format server-side.
SMS is billed per segment: 1 credit per 160 characters for plain GSM-7 text, or 1 credit per 70 characters once the message contains any Unicode (emoji, non-Latin script). Sends that would exceed your remaining balance return 422 with the shape:
{ "message": "Insufficient SMS balance...", "balance": 0, "required": 2 }
Validation errors follow Laravel's default shape:
{
"message": "The given data was invalid.",
"errors": { "to": ["The to field is required."] }
}
Other errors are { "message": "..." } with an appropriate HTTP status (401, 403, 404, 422, 429, 500, 502).
Account creation, login, and password management. All endpoints here except Get Current User / Profile / Logout are public (no token required).
/register
No auth required
Self-service sign-up. Creates a new tenant organization plus its first admin user, and returns a Bearer token you can use immediately — no separate login call needed.
The org_name is slugified to derive a unique organization slug; if the slug or email is already taken you get a 422.
| Content-Type | application/json |
| Accept | application/json |
{
"org_name": "Acme Traders",
"phone": "255712345678",
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"password": "SecurePass123",
"password_confirmation": "SecurePass123"
}
curl --location --request POST 'https://mosms.co.tz/api/register' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"org_name": "Acme Traders",
"phone": "255712345678",
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"password": "SecurePass123",
"password_confirmation": "SecurePass123"
}'
{
"message": "Registration successful.",
"token": "1|abcdEFGH1234567890tokenExample",
"user_type": "user",
"user": {
"id": 12,
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"role": "admin",
"tenant": {
"id": 7,
"name": "Acme Traders",
"slug": "acme-traders"
}
}
}{
"message": "An organization with this name already exists."
}/login
No auth required
Unified login for both tenant (developer) accounts and platform Super Admins — it checks the admin table first, then falls back to tenant users. Returns a Sanctum Bearer token to use on every subsequent request as Authorization: Bearer <token>, plus the caller's permissions list (granular RBAC — check this before assuming an endpoint is reachable).
| Content-Type | application/json |
| Accept | application/json |
{
"email": "jane@acme.co.tz",
"password": "SecurePass123"
}
curl --location --request POST 'https://mosms.co.tz/api/login' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"email": "jane@acme.co.tz",
"password": "SecurePass123"
}'
{
"token": "1|abcdEFGH1234567890tokenExample",
"user_type": "user",
"user": {
"id": 12,
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"role": "admin",
"tenant": {
"id": 7,
"name": "Acme Traders",
"slug": "acme-traders"
}
},
"permissions": [
"dashboard",
"messages",
"messages.send",
"bulk_sms.send",
"group_sms.send",
"contacts",
"groups",
"templates"
]
}{
"message": "Invalid credentials."
}{
"message": "Your organization is inactive. Contact support."
}/forgot-password
No auth required
Requests a password-reset email. Always returns 200 regardless of whether the email exists, to avoid leaking which emails are registered.
| Content-Type | application/json |
| Accept | application/json |
{
"email": "jane@acme.co.tz"
}
curl --location --request POST 'https://mosms.co.tz/api/forgot-password' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"email": "jane@acme.co.tz"
}'
{
"message": "If that email exists, a reset link has been sent."
}/reset-password
No auth required
Completes a password reset using the token emailed by Forgot Password. Tokens expire after 60 minutes.
| Content-Type | application/json |
| Accept | application/json |
{
"token": "the-token-from-the-email",
"email": "jane@acme.co.tz",
"password": "NewSecurePass456",
"password_confirmation": "NewSecurePass456"
}
curl --location --request POST 'https://mosms.co.tz/api/reset-password' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"token": "the-token-from-the-email",
"email": "jane@acme.co.tz",
"password": "NewSecurePass456",
"password_confirmation": "NewSecurePass456"
}'
{
"message": "Your password has been reset. You can now log in."
}{
"message": "This reset link is invalid or has already been used."
}/me
Returns the authenticated user's profile, tenant, and permission list. Useful right after login to confirm the token works and to know what the caller is allowed to do.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/me' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/profile
Returns the authenticated user's profile (id, name, email, role, tenant).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/profile' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/profile
Updates the caller's name/email, and optionally changes password (requires current_password).
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"current_password": "SecurePass123",
"new_password": "EvenMoreSecure789",
"new_password_confirmation": "EvenMoreSecure789"
}
curl --location --request PATCH 'https://mosms.co.tz/api/profile' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Jane Doe",
"email": "jane@acme.co.tz",
"current_password": "SecurePass123",
"new_password": "EvenMoreSecure789",
"new_password_confirmation": "EvenMoreSecure789"
}'
/logout
Revokes the Bearer token used on this request. Call this when a client (script, app) is done using its token.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request POST 'https://mosms.co.tz/api/logout' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
Account-level summary data and SMS credit balance.
/balance
Returns the tenant's remaining SMS credit balance. Check this before sending to avoid a 422 insufficient-balance error — 1 credit = 1 SMS segment (see Send Single SMS for segment math).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/balance' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"sms_balance": 1520
}/dashboard
Aggregate counters for the tenant: users, contacts, groups, messages (total + today), plus upcoming holiday/birthday auto-wish previews.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/dashboard' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"users_count": 3,
"contacts_count": 240,
"groups_count": 5,
"messages_count": 18432,
"messages_today": 56,
"upcoming_holiday": null,
"upcoming_birthdays": [
{
"id": 4,
"name": "Amina Suleiman",
"phone": "255712345678",
"birth_date": "1990-07-20",
"days_until": 3,
"upcoming_age": 36
}
],
"birthday_wishes_enabled": true
}The core sending endpoints — single message, bulk batch, or a saved group.
/sms/send
Sends one SMS immediately (or schedules it for later with scheduled_at). Requires the messages.send permission.
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
to | string | yes | Any reasonable format (0712345678, +255712345678, 255712345678) — normalized server-side. |
text | string | required unless template_id given | Max 4000 chars. |
contact_id | integer | no | Links the message to an existing contact. |
template_id | integer | no | Renders a saved template ({name}, {phone}, {email} placeholders) instead of text. |
scheduled_at | datetime | no | ISO date-time in the future — queues the send instead of sending now. |
Credit cost: GSM-7 messages cost 1 credit per 160 characters; messages containing Unicode (emoji, non-Latin scripts) cost 1 credit per 70 characters. The gateway rejects the request with 422 if your balance can't cover the segment count.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"to": "0712345678",
"text": "Hello from MoSMS!",
"scheduled_at": null
}
curl --location --request POST 'https://mosms.co.tz/api/sms/send' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"to": "0712345678",
"text": "Hello from MoSMS!",
"scheduled_at": null
}'
{
"data": {
"id": 1042,
"to_number": "255712345678",
"from_sender": "MOSMS",
"body": "Hello from MoSMS!",
"status": "PENDING_ACCEPTED",
"delivery_status": null,
"delivered_at": null,
"delivery_error": null,
"gateway_message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"gateway_response": {
"messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"sent_at": "2026-07-17T10:00:00.000000Z",
"scheduled_at": null,
"contact": null,
"group": null,
"user": null,
"created_at": "2026-07-17T10:00:00.000000Z"
}
}{
"message": "Insufficient SMS balance. Message requires 2 credit(s) but you have 0 remaining.",
"balance": 0,
"required": 2
}/sms/send-bulk
Queues up to any number of distinct messages for background delivery (does not send synchronously — you'll get a 202 immediately, then track each message via List Messages). Requires bulk_sms.send.
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
messages | array | yes | At least 1 item: { "to": "...", "text": "...", "contact_id": null }. |
messages[].to | string | yes | Recipient number. |
messages[].text | string | required unless template_id given | Per-message text (max 4000 chars). |
template_id | integer | no | Applies one template to every message in the array, with per-contact placeholder rendering. |
scheduled_at | datetime | no | Delays the whole batch. |
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"messages": [
{
"to": "0712345678",
"text": "Hi Juma, your order has shipped!"
},
{
"to": "0765432109",
"text": "Hi Amina, your order has shipped!"
}
]
}
curl --location --request POST 'https://mosms.co.tz/api/sms/send-bulk' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"messages": [
{
"to": "0712345678",
"text": "Hi Juma, your order has shipped!"
},
{
"to": "0765432109",
"text": "Hi Amina, your order has shipped!"
}
]
}'
{
"message": "Bulk SMS queued for delivery.",
"count": 2
}{
"message": "Insufficient SMS balance. Messages require 2 credit(s) but you have 0 remaining.",
"balance": 0,
"required": 2
}/sms/send-group/:group_id
Sends (queues) the same message to every contact in a saved Group. Requires group_sms.send.
Path parameter: group_id — the group's numeric ID (see Groups folder).
Body: same text / template_id / scheduled_at fields as Send Single SMS. Returns 422 if the group has no contacts or the balance can't cover contacts_count × segments_per_message.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"text": "Reminder: our office is closed tomorrow for the public holiday.",
"template_id": null,
"scheduled_at": null
}
curl --location --request POST 'https://mosms.co.tz/api/sms/send-group/:group_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"text": "Reminder: our office is closed tomorrow for the public holiday.",
"template_id": null,
"scheduled_at": null
}'
{
"message": "Group SMS to 'VIP Customers' queued for delivery.",
"contacts": 84
}{
"message": "Group has no contacts."
}Message history, delivery-status polling, cancellation, and deletion.
/messages
Paginated history of every message sent (or queued/scheduled) by the tenant, newest first.
Query parameters (all optional): status (e.g. PENDING_ACCEPTED, DELIVERED, scheduled, cancelled), search (matches to_number or body), date_from, date_to (both YYYY-MM-DD, filtered on sent_at), page.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| status | Filter by delivery/send status |
| search | Search phone number or message body |
| date_from | YYYY-MM-DD |
| date_to | YYYY-MM-DD |
| page | Pagination page number |
curl --location --request GET 'https://mosms.co.tz/api/messages' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": [
{
"id": 1042,
"to_number": "255712345678",
"from_sender": "MOSMS",
"body": "Hello from MoSMS!",
"status": "DELIVERED",
"delivery_status": "DELIVERED_TO_HANDSET",
"delivered_at": "2026-07-17T10:00:05.000000Z",
"delivery_error": null,
"gateway_message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sent_at": "2026-07-17T10:00:00.000000Z",
"scheduled_at": null,
"created_at": "2026-07-17T10:00:00.000000Z"
}
],
"links": {
"first": "https://mosms.co.tz/api/messages?page=1",
"last": "https://mosms.co.tz/api/messages?page=12",
"prev": null,
"next": "https://mosms.co.tz/api/messages?page=2"
},
"meta": {
"current_page": 1,
"last_page": 12,
"per_page": 20,
"total": 231
}
}/messages/:message_id
Fetches a single message by ID, with its linked contact/group/user (when present).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/messages/:message_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/messages/:message_id/check-status
Actively polls the upstream SMS gateway for the latest delivery report on this message and updates status / delivery_status / delivered_at / delivery_error accordingly, then returns the refreshed message. Requires messages.check_status.
Errors: 422 if the message has no gateway_message_id (e.g. it's still scheduled), 404 if the gateway has no report yet, 429 if the gateway rate-limited us, 502 if the gateway is unreachable.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request POST 'https://mosms.co.tz/api/messages/:message_id/check-status' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": {
"id": 1042,
"to_number": "255712345678",
"status": "DELIVERED",
"delivery_status": "DELIVERED_TO_HANDSET",
"delivered_at": "2026-07-17T10:00:05.000000Z",
"delivery_error": null
}
}{
"message": "This message has no gateway ID \u2014 status cannot be checked."
}/messages/:message_id/cancel
Cancels a message that hasn't been sent yet (status === 'scheduled'). Requires messages.cancel_scheduled. Returns 422 if the message already sent.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request POST 'https://mosms.co.tz/api/messages/:message_id/cancel' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"message": "Only scheduled messages can be cancelled."
}/messages/bulk
Permanently deletes multiple message records by ID. Requires messages.delete.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"ids": [
1042,
1043,
1044
]
}
curl --location --request DELETE 'https://mosms.co.tz/api/messages/bulk' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"ids": [
1042,
1043,
1044
]
}'
{
"message": "Messages deleted.",
"count": 3
}Raw records proxied from the upstream SMS gateway, for reconciliation.
/delivery-reports
Proxies straight through to the upstream carrier's native delivery-report endpoint and returns its raw JSON — useful for reconciling against gateway-side records directly. Requires delivery_reports.
Query: messageId (optional, filters to one message), limit (default 25).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| messageId | Filter to a single gateway message ID |
| limit | Max results to return |
curl --location --request GET 'https://mosms.co.tz/api/delivery-reports' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"message": "Unable to reach the SMS gateway. Please try again later."
}/sms-logs
Tenant-scoped raw send logs proxied from the upstream gateway (distinct from List Messages, which is MoSMS's own local record). Requires sms_logs.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/sms-logs' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
Manage the tenant's contact book, including CSV/vCard bulk import.
/contacts
Paginated contact list. Query: search (matches name/phone), page.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| search | Search by name or phone |
| page |
curl --location --request GET 'https://mosms.co.tz/api/contacts' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": [
{
"id": 501,
"name": "Juma Hassan",
"phone": "255712345678",
"email": null,
"birth_date": null,
"groups": [],
"created_at": "2026-01-10T08:00:00.000000Z",
"updated_at": "2026-01-10T08:00:00.000000Z"
}
],
"links": {},
"meta": {
"current_page": 1,
"last_page": 3,
"per_page": 20,
"total": 58
}
}/contacts
name and phone are required; phone must be unique per tenant (normalized before the uniqueness check). birth_date (if set) powers the birthday auto-SMS feature.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Juma Hassan",
"phone": "0712345678",
"email": "juma@example.com",
"birth_date": "1988-03-14"
}
curl --location --request POST 'https://mosms.co.tz/api/contacts' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Juma Hassan",
"phone": "0712345678",
"email": "juma@example.com",
"birth_date": "1988-03-14"
}'
{
"data": {
"id": 501,
"name": "Juma Hassan",
"phone": "255712345678",
"email": "juma@example.com",
"birth_date": "1988-03-14",
"groups": []
}
}/contacts/:contact_id
Fetch one contact with its groups loaded.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/contacts/:contact_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/contacts/:contact_id
All fields optional (sometimes validation) — send only what changes.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Juma Hassan Mnyonge",
"phone": "0712345678",
"email": "juma@example.com"
}
curl --location --request PUT 'https://mosms.co.tz/api/contacts/:contact_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Juma Hassan Mnyonge",
"phone": "0712345678",
"email": "juma@example.com"
}'
/contacts/:contact_id
Permanently deletes one contact.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/contacts/:contact_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/contacts/bulk
Deletes multiple contacts by ID.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"ids": [
501,
502,
503
]
}
curl --location --request DELETE 'https://mosms.co.tz/api/contacts/bulk' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"ids": [
501,
502,
503
]
}'
{
"message": "Contacts deleted.",
"count": 3
}/contacts/import/csv
Multipart upload. CSV columns: name, phone, email, birth_date (header row required). Max 5MB.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| file | CSV file — columns: name, phone, email, birth_date |
curl --location --request POST 'https://mosms.co.tz/api/contacts/import/csv' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--form 'file=@/path/to/your/file'
/contacts/import/vcf
Multipart upload of a .vcf vCard export (e.g. exported from a phone's contacts app). Max 5MB.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| file | vCard (.vcf) file |
curl --location --request POST 'https://mosms.co.tz/api/contacts/import/vcf' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--form 'file=@/path/to/your/file'
Organize contacts into groups for targeted group sends.
/groups
Paginated list of contact groups, with contacts_count on each.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/groups' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": [
{
"id": 9,
"name": "VIP Customers",
"description": "Top-tier clients",
"contacts_count": 84,
"created_at": "2026-02-01T00:00:00.000000Z",
"updated_at": "2026-02-01T00:00:00.000000Z"
}
]
}/groups
Creates an empty group — add contacts afterwards via Add Contacts to Group.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "VIP Customers",
"description": "Top-tier clients"
}
curl --location --request POST 'https://mosms.co.tz/api/groups' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "VIP Customers",
"description": "Top-tier clients"
}'
{
"data": {
"id": 9,
"name": "VIP Customers",
"description": "Top-tier clients",
"contacts_count": 0
}
}/groups/:group_id
Fetch one group with its contacts_count.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/groups/:group_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/groups/:group_id
Rename a group or change its description.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "VIP Customers (Tier 1)",
"description": "Top-tier clients"
}
curl --location --request PUT 'https://mosms.co.tz/api/groups/:group_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "VIP Customers (Tier 1)",
"description": "Top-tier clients"
}'
/groups/:group_id
Deletes the group (contacts themselves are not deleted, only the grouping).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/groups/:group_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/groups/:group_id/contacts
Paginated list of contacts that belong to this group.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/groups/:group_id/contacts' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/groups/:group_id/contacts
Attaches existing contacts (by ID) to the group — safe to call repeatedly, duplicates are ignored.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"contact_ids": [
501,
502,
503
]
}
curl --location --request POST 'https://mosms.co.tz/api/groups/:group_id/contacts' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"contact_ids": [
501,
502,
503
]
}'
{
"message": "Contacts added to group."
}/groups/:group_id/contacts
Detaches contacts from the group without deleting the contacts themselves.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"contact_ids": [
501
]
}
curl --location --request DELETE 'https://mosms.co.tz/api/groups/:group_id/contacts' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"contact_ids": [
501
]
}'
{
"message": "Contacts removed from group."
}Reusable message bodies with {name}/{phone}/{email} placeholders.
/templates
Paginated list of saved message templates.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/templates' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/templates
body supports {name}, {phone}, and {email} placeholders, filled in per-contact when the template is used in a send.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Order Shipped",
"body": "Hi {name}, your order has shipped! Track it at example.com/track."
}
curl --location --request POST 'https://mosms.co.tz/api/templates' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Order Shipped",
"body": "Hi {name}, your order has shipped! Track it at example.com/track."
}'
{
"data": {
"id": 3,
"name": "Order Shipped",
"body": "Hi {name}, your order has shipped! Track it at example.com/track.",
"created_at": "2026-01-05T00:00:00.000000Z"
}
}/templates/:template_id
Fetch one template.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/templates/:template_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/templates/:template_id
Updates a template's name and/or body.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Order Shipped",
"body": "Hi {name}, your order #{phone} has shipped!"
}
curl --location --request PUT 'https://mosms.co.tz/api/templates/:template_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Order Shipped",
"body": "Hi {name}, your order #{phone} has shipped!"
}'
/templates/:template_id
Deletes a template.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/templates/:template_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
Buying more SMS/WhatsApp credits — manual (admin-approved) or online via Pesapal.
/sms-packages
Public price tiers available for purchase (no purchase_sms permission required to view).
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/sms-packages' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": [
{
"id": 1,
"name": "Starter",
"min_quantity": 100,
"max_quantity": 999,
"price_per_sms": 20
},
{
"id": 2,
"name": "Growth",
"min_quantity": 1000,
"max_quantity": 9999,
"price_per_sms": 18
}
]
}/sms-purchases
Submits a manual top-up request (e.g. after a bank/mobile-money transfer) for admin approval — credits are not added instantly. sms_quantity must be ≥100 for SMS or ≥10 for channel: whatsapp. Only one pending manual request per channel is allowed at a time.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"sms_quantity": 1000,
"transaction_reference": "MPESA-XJ29KD8",
"payer_phone": "0712345678"
}
curl --location --request POST 'https://mosms.co.tz/api/sms-purchases' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"sms_quantity": 1000,
"transaction_reference": "MPESA-XJ29KD8",
"payer_phone": "0712345678"
}'
{
"message": "Purchase request submitted successfully.",
"data": {
"id": 88,
"sms_quantity": 1000,
"total_amount": 20000,
"status": "pending"
}
}{
"message": "You already have a pending SMS purchase of 500 credits (Ref: MPESA-AB12CD) awaiting approval. Please wait for it to be approved before creating a new one.",
"pending_id": 87
}/sms-purchases/pesapal
Initiates an online card/mobile-money checkout through Pesapal. Returns a redirect_url — send the user there to complete payment, then poll Check Pesapal Purchase Status.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"sms_quantity": 1000
}
curl --location --request POST 'https://mosms.co.tz/api/sms-purchases/pesapal' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"sms_quantity": 1000
}'
{
"message": "Pesapal checkout initiated.",
"data": {
"payment_id": 89,
"redirect_url": "https://pay.pesapal.com/...",
"order_tracking_id": "..."
}
}/sms-purchases/:purchase_id/status
Polls Pesapal for the latest status of a pending online payment and updates the local record.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/sms-purchases/:purchase_id/status' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": {
"id": 89,
"status": "approved",
"payment_status_description": "COMPLETED",
"confirmation_code": "ABC123",
"payment_method": "pesapal",
"sms_quantity": 1000,
"total_amount": 18000
}
}/sms-purchases
Paginated history of the tenant's SMS/WhatsApp credit purchases.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/sms-purchases' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/sms-purchases/:purchase_id/receipt
Streams a PDF receipt for an approved purchase. Only available once status === 'approved'.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/sms-purchases/:purchase_id/receipt' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
Weddings, harambees, and fundraisers — invitees, pledge/payment tracking, and multi-stage SMS/WhatsApp campaigns (invitations, reminders, thank-yous).
/events
Paginated list of events (weddings, harambees/fundraisers, etc.) with computed SMS-cost stats. Requires events. Query: search (matches name), status (draft/active/completed/cancelled), page.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| search | Search by event name |
| status | draft|active|completed|cancelled |
| page |
curl --location --request GET 'https://mosms.co.tz/api/events' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"data": [
{
"id": 12,
"name": "Amina & Juma's Wedding",
"type": "wedding",
"description": null,
"event_date": "2026-09-12",
"venue": "Kigamboni Beach Hall",
"target_amount": 5000000,
"status": "active",
"invitees_count": 84,
"payments_count": 12,
"sms_stages_count": 3,
"total_pledged": 3200000,
"total_collected": 1450000,
"total_sms": 252,
"sent_sms": 84,
"sms_cost": 5040,
"created_at": "2026-06-01T09:00:00.000000Z"
}
]
}/events
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | |
type | string | yes | wedding, harambee, fundraiser, or other. |
event_date | date | yes | |
description | string | no | Max 2000 chars. |
venue | string | no | |
target_amount | number | no | Fundraising target, if any. |
status | string | no | draft, active, completed, or cancelled (default draft). |
public_message | string | no | Shown on the public RSVP/pledge page. |
bank_name / bank_account_number / bank_account_name | string | no | For displaying payment instructions publicly. |
pledge_deadline | date | no |
Requires events.add.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Amina & Juma's Wedding",
"type": "wedding",
"event_date": "2026-09-12",
"venue": "Kigamboni Beach Hall",
"target_amount": 5000000
}
curl --location --request POST 'https://mosms.co.tz/api/events' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Amina & Juma'\''s Wedding",
"type": "wedding",
"event_date": "2026-09-12",
"venue": "Kigamboni Beach Hall",
"target_amount": 5000000
}'
{
"data": {
"id": 12,
"name": "Amina & Juma's Wedding",
"type": "wedding",
"event_date": "2026-09-12",
"status": "draft",
"invitees_count": 0
}
}/events/:event_id
Fetch one event, including total_pledged/total_collected totals. Requires events.view.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/events/:event_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id
Same fields as Create Event, all optional (sometimes validation). Requires events.edit.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"status": "active"
}
curl --location --request PUT 'https://mosms.co.tz/api/events/:event_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"status": "active"
}'
/events/:event_id
Requires events.delete. This also removes the event's invitees, payments, and SMS stages.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/events/:event_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/invitees
Paginated. Query: search (matches name/phone), page. Requires events.view.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| search | Search by name or phone |
| page |
curl --location --request GET 'https://mosms.co.tz/api/events/:event_id/invitees' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/invitees
name and phone required; pledge_amount and contact_id (link to an existing Contact) optional. Requires events.manage_invitees.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"name": "Fatuma Rajabu",
"phone": "0712345678",
"pledge_amount": 50000
}
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/invitees' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"name": "Fatuma Rajabu",
"phone": "0712345678",
"pledge_amount": 50000
}'
{
"data": {
"id": 501,
"event_id": 12,
"name": "Fatuma Rajabu",
"phone": "255712345678",
"pledge_amount": 50000,
"paid_amount": 0,
"status": "pending"
}
}/events/:event_id/invitees/import
Bulk-adds invitees from existing Contacts and/or a Group — pass contact_ids (array) and/or group_id (at least one required). Duplicates (already-invited contacts) are skipped. Requires events.manage_invitees.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"group_id": 9,
"contact_ids": [
501,
502
]
}
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/invitees/import' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"group_id": 9,
"contact_ids": [
501,
502
]
}'
{
"message": "42 invitees imported.",
"imported": 42
}/events/:event_id/invitees/import/file
Multipart upload — CSV (with name/phone/email columns) or .vcf vCard export. Max 5MB. Requires events.manage_invitees.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
| file | CSV or .vcf file |
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/invitees/import/file' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json' \
--form 'file=@/path/to/your/file'
{
"message": "38 invitees imported, 4 skipped.",
"imported": 38,
"skipped": 4
}/events/:event_id/invitees/:invitee_id
All fields optional. status is one of pending, invited, confirmed, declined. Requires events.manage_invitees.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"status": "confirmed",
"pledge_amount": 60000
}
curl --location --request PUT 'https://mosms.co.tz/api/events/:event_id/invitees/:invitee_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"status": "confirmed",
"pledge_amount": 60000
}'
/events/:event_id/invitees/:invitee_id
Requires events.manage_invitees.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/events/:event_id/invitees/:invitee_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/payments
Paginated, newest first, with invitee + recorder loaded. Requires events.view.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/events/:event_id/payments' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/payments
Records a pledge payment against an invitee. If the event has auto_payment_sms enabled, a thank-you SMS is sent automatically. Requires events.manage_payments.
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
event_invitee_id | integer | yes | Must belong to this event. |
amount | number | yes | > 0. |
payment_date | date | yes | |
payment_method | string | no | cash, mobile_money, bank, or other. |
reference | string | no | e.g. mobile money transaction ID. |
notes | string | no |
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"event_invitee_id": 501,
"amount": 50000,
"payment_method": "mobile_money",
"reference": "MPESA-XJ29KD8",
"payment_date": "2026-07-18"
}
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/payments' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"event_invitee_id": 501,
"amount": 50000,
"payment_method": "mobile_money",
"reference": "MPESA-XJ29KD8",
"payment_date": "2026-07-18"
}'
{
"data": {
"id": 88,
"event_id": 12,
"event_invitee_id": 501,
"amount": 50000,
"payment_method": "mobile_money",
"reference": "MPESA-XJ29KD8",
"payment_date": "2026-07-18"
}
}/events/:event_id/payments/:payment_id
All fields optional. Requires events.manage_payments.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"amount": 55000
}
curl --location --request PUT 'https://mosms.co.tz/api/events/:event_id/payments/:payment_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"amount": 55000
}'
/events/:event_id/payments/:payment_id
Requires events.manage_payments.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/events/:event_id/payments/:payment_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/sms-stages
Each stage includes computed stage_total_sms/stage_remaining/stage_cost based on the current invitee count. Requires events.view.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request GET 'https://mosms.co.tz/api/events/:event_id/sms-stages' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/sms-stages
Defines a message (SMS or WhatsApp) to send to all invitees, once or on a recurring schedule. SMS and WhatsApp are always separate stages — there's no combined "both" channel; create one stage per channel if you want to reach invitees on both. Requires events.send_sms.
Body parameters
| Field | Type | Required | Notes |
|---|---|---|---|
stage_type | string | yes | invitation, reminder, pledge_reminder, non_pledge_reminder, thank_you, rsvp, or custom. |
name | string | yes | Internal label. |
body | string | yes | Max 4000 chars. Supports placeholders like {invitee_name}, {event_name}, {event_date}, {venue}, {pledge_amount}, {event_link}. |
channel | string | no | sms (default) or whatsapp. |
whatsapp_template_id | integer | required if channel=whatsapp | Must be an approved WhatsApp template. |
send_at | datetime | no | First/only send time. |
frequency | string | no | once, daily, weekly, or monthly. |
end_at | date | no | Required alongside a recurring frequency; must be ≥ send_at. |
status | string | no | draft or scheduled. |
Creating a stage does not send it — call Send SMS Stage (or let it fire on send_at).
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"stage_type": "invitation",
"name": "Save the Date",
"channel": "sms",
"body": "You're invited to {invitee_name}'s wedding on {event_date} at {venue}!",
"send_at": "2026-08-01T09:00:00",
"frequency": "once"
}
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/sms-stages' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"stage_type": "invitation",
"name": "Save the Date",
"channel": "sms",
"body": "You'\''re invited to {invitee_name}'\''s wedding on {event_date} at {venue}!",
"send_at": "2026-08-01T09:00:00",
"frequency": "once"
}'
{
"data": {
"id": 7,
"event_id": 12,
"stage_type": "invitation",
"name": "Save the Date",
"status": "draft",
"sent_count": 0
}
}/events/:event_id/sms-stages/:stage_id
Same fields as Create SMS Stage. status may additionally be set to cancelled. Requires events.send_sms.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"status": "scheduled"
}
curl --location --request PUT 'https://mosms.co.tz/api/events/:event_id/sms-stages/:stage_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"status": "scheduled"
}'
/events/:event_id/sms-stages/:stage_id
Requires events.send_sms.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request DELETE 'https://mosms.co.tz/api/events/:event_id/sms-stages/:stage_id' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
/events/:event_id/sms-stages/:stage_id/send
Queues the stage's message to every eligible invitee now. WhatsApp stages are metered against the tenant's WhatsApp wallet (not the SMS balance) and billed per conversation. SMS stages are checked against the SMS credit balance the same way as Send SMS to Group. Requires events.send_sms.
| Authorization | Bearer YOUR_TOKEN |
| Accept | application/json |
curl --location --request POST 'https://mosms.co.tz/api/events/:event_id/sms-stages/:stage_id/send' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Accept: application/json'
{
"message": "Sending 84 message(s). You'll be notified when complete."
}{
"message": "This stage has already been sent."
}{
"message": "No invitees are eligible for this stage."
}Inbound callbacks that MoSMS itself receives from the SMS carrier and Meta. Not callable by API clients — included so the origin of delivery-status updates is clear.
/webhooks/delivery
No auth required
Not called by developers. This is the endpoint the upstream SMS carrier calls to push delivery-status updates for messages MoSMS sent on your behalf. Documented here only so you understand where delivery_status on a message comes from — you don't need to (and can't meaningfully) call this yourself.
There is currently no outbound webhook that notifies *your* systems when a message's status changes — poll Check Delivery Status or List Messages instead.
| Content-Type | application/json |
| Accept | application/json |
{
"messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "DELIVERED_TO_HANDSET",
"error": null
}
curl --location --request POST 'https://mosms.co.tz/api/webhooks/delivery' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "DELIVERED_TO_HANDSET",
"error": null
}'
{
"message": "OK"
}/webhooks/whatsapp?hub.mode=subscribe&hub.verify_token=...&hub.challenge=...
No auth required
Not called by developers. Meta's webhook-verification handshake for the tenant's WhatsApp Cloud API integration.
| Accept | application/json |
| hub.mode | |
| hub.verify_token | |
| hub.challenge |
curl --location --request GET 'https://mosms.co.tz/api/webhooks/whatsapp?hub.mode=subscribe&hub.verify_token=...&hub.challenge=...' \
--header 'Accept: application/json'
/webhooks/whatsapp
No auth required
Not called by developers. Meta pushes WhatsApp delivery statuses (sent/delivered/read/failed) and inbound message replies here. Verified via X-Hub-Signature-256 HMAC when WHATSAPP_APP_SECRET is configured.
| Accept | application/json |
curl --location --request POST 'https://mosms.co.tz/api/webhooks/whatsapp' \
--header 'Accept: application/json'
WhatsApp sending currently only exists in MoSMS's internal dashboard (session auth), not this token-based developer API. These items sketch the likely shape of a future public endpoint for planning purposes — not live, subject to change.
/whatsapp/send
⚠️ Not yet available on the public API. WhatsApp sending today only exists in the internal MoSMS dashboard (session-authenticated web routes), metered against the tenant's whatsapp_balance wallet — mirroring Send Single SMS, but via App\Services\WhatsApp\WhatsAppCloudService instead of the SMS gateway.
This item documents the shape a future token-authenticated /api/whatsapp/send endpoint would likely take, based on the existing dashboard implementation, so client integrations can be planned ahead of time. Confirm with the MoSMS team before building against it.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"to": "0712345678",
"whatsapp_template_id": 4,
"text": null
}
curl --location --request POST 'https://mosms.co.tz/api/whatsapp/send' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"to": "0712345678",
"whatsapp_template_id": 4,
"text": null
}'
/whatsapp/send-bulk
⚠️ Not yet available on the public API. Modeled on the internal bulk/group broadcast flow (channel: whatsapp), which requires an approved, no-variable WhatsApp template and is metered 1 WhatsApp credit per recipient. Confirm with the MoSMS team before building against it.
| Authorization | Bearer YOUR_TOKEN |
| Content-Type | application/json |
| Accept | application/json |
{
"numbers": [
"0712345678",
"0765432109"
],
"whatsapp_template_id": 4
}
curl --location --request POST 'https://mosms.co.tz/api/whatsapp/send-bulk' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"numbers": [
"0712345678",
"0765432109"
],
"whatsapp_template_id": 4
}'