Introduction
Send SMS, track delivery and pull reporting straight from your own systems.
Welcome to the MasokoDigital API.
This reference covers everything you need to send SMS from your own application, check what was delivered, and pull reporting back out - the same capabilities the dashboard uses.
Getting your credentials
Sign in, open API Access from the sidebar, and request your credentials. You will get an API key and an API token. Treat the token like a password: anyone holding it can send messages billed to your account.
Authenticating
Every request needs a Bearer token and a JSON Accept header:
curl -X GET "{base_url}/api/sms/balance" \
-H "Authorization: Bearer <your-api-token>" \
-H "Accept: application/json"
Requests without a valid token return 401.
Before you send
A message needs an approved sender ID. Call GET /api/sms/senders to see which of yours
are usable - sending with an unapproved one returns 404 Sender ID Not Found. You also need
SMS credits; check them with GET /api/sms/balance.
Sending
Use /api/sms/send/single for one recipient and /api/sms/send/bulk for many in one call.
Both return a campaign_id. Keep it - it is what you pass to the campaign statistics and
delivery report endpoints. If you lose it, GET /api/sms/campaigns lists your campaigns
newest first.
Reading results
Delivery is asynchronous, so a campaign is rarely final the moment it is accepted. Poll
GET /api/campaign/sms/statistics/{campaign} for totals, or GET /api/sms/report/{campaign}/{phone}
for one recipient. For analysis over a period, GET /api/sms/campaign/report/dates breaks
results down by status, gender, age band and location.
Conventions
All responses are JSON. Errors carry an error key and the matching HTTP status - 400 for
validation, 401 for authentication, 404 when something is not found.
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
You can retrieve your token by visiting your profile and clicking Request on API access section.
SMS
Send messages, check your balance, and pull delivery reporting.
Send a single SMS
requires authentication
Sends one message to one recipient. The sender ID must already be
approved - call GET /api/sms/senders to see which of yours are.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post(
'https://masokodigital.co.tz/api/sms/send/single',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'sender_id' => 'MASOKO',
'message' => 'Hello from MasokoDigital',
'recipient' => '255700000000',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/send/single'
payload = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipient": "255700000000"
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('POST', url, headers=headers, json=payload)
response.json()
require 'rest-client'
body = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipient": "255700000000"
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.post(
'https://masokodigital.co.tz/api/sms/send/single',
body ,
headers
)
p response.body
curl --request POST \
"https://masokodigital.co.tz/api/sms/send/single" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"sender_id\": \"MASOKO\",
\"message\": \"Hello from MasokoDigital\",
\"recipient\": \"255700000000\"
}"
const url = new URL(
"https://masokodigital.co.tz/api/sms/send/single"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipient": "255700000000"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "2026-08-12 09:00:00 API campaign SMS Campaign Processing...",
"status": "Processing",
"campaign_id": "9b1f...c3"
}
Example response (400):
{
"error": {
"recipient": [
"The recipient field is required."
]
}
}
Example response (404):
{
"error": "Sender ID Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Send bulk SMS
requires authentication
Sends the same message to many recipients in one call. Recipients are processed in chunks; the response returns as soon as the campaign is accepted, so poll the campaign statistics endpoint for delivery.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post(
'https://masokodigital.co.tz/api/sms/send/bulk',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'sender_id' => 'MASOKO',
'message' => 'Hello from MasokoDigital',
'recipients' => ['255700000000', '255711111111'],
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/send/bulk'
payload = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipients": [
"255700000000",
"255711111111"
]
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('POST', url, headers=headers, json=payload)
response.json()
require 'rest-client'
body = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipients": [
"255700000000",
"255711111111"
]
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.post(
'https://masokodigital.co.tz/api/sms/send/bulk',
body ,
headers
)
p response.body
curl --request POST \
"https://masokodigital.co.tz/api/sms/send/bulk" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"sender_id\": \"MASOKO\",
\"message\": \"Hello from MasokoDigital\",
\"recipients\": [
\"255700000000\",
\"255711111111\"
]
}"
const url = new URL(
"https://masokodigital.co.tz/api/sms/send/bulk"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"sender_id": "MASOKO",
"message": "Hello from MasokoDigital",
"recipients": [
"255700000000",
"255711111111"
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "2026-08-12 09:00:00 API campaign SMS Campaign Processing...",
"status": "Processing",
"campaign_id": "9b1f...c3"
}
Example response (400):
{
"error": "Campaign has no contacts"
}
Example response (404):
{
"error": "Sender ID Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get SMS balance
requires authentication
Remaining SMS credits on your account.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/balance',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/balance'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/balance',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/balance" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/sms/balance"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"balance": 4612
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Message counts by status
requires authentication
Totals per delivery status over a date range.
The message field is a legacy string kept for existing integrations;
prefer the data object, which carries the same counts keyed by status.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/campaign/sms/report',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'start' => '2026-01-01',
'end' => '2026-12-31',
],
'json' => [
'start' => '2026-09-06T16:14:20',
'end' => '2026-09-06T16:14:20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/campaign/sms/report'
payload = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
}
params = {
'start': '2026-01-01',
'end': '2026-12-31',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
require 'rest-client'
body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/campaign/sms/report',
body ,
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/campaign/sms/report?start=2026-01-01&end=2026-12-31" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"start\": \"2026-09-06T16:14:20\",
\"end\": \"2026-09-06T16:14:20\"
}"
const url = new URL(
"https://masokodigital.co.tz/api/campaign/sms/report"
);
const params = {
"start": "2026-01-01",
"end": "2026-12-31",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "[\"DELIVRD\",\"Success\"] -> [155,614]",
"data": {
"DELIVRD": 155,
"Success": 614
},
"total": 769,
"start": "2026-01-01T00:00:00.000000Z",
"end": null
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List campaigns
requires authentication
Your campaigns, newest first. Useful for recovering a campaign_id you
did not keep from the send response.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/campaigns',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'start' => '2026-01-01',
'end' => '2026-12-31',
'per_page' => '50',
],
'json' => [
'start' => '2026-09-06T16:14:20',
'end' => '2026-09-06T16:14:20',
'per_page' => 21,
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/campaigns'
payload = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20",
"per_page": 21
}
params = {
'start': '2026-01-01',
'end': '2026-12-31',
'per_page': '50',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
require 'rest-client'
body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20",
"per_page": 21
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/campaigns',
body ,
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/campaigns?start=2026-01-01&end=2026-12-31&per_page=50" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"start\": \"2026-09-06T16:14:20\",
\"end\": \"2026-09-06T16:14:20\",
\"per_page\": 21
}"
const url = new URL(
"https://masokodigital.co.tz/api/sms/campaigns"
);
const params = {
"start": "2026-01-01",
"end": "2026-12-31",
"per_page": "50",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20",
"per_page": 21
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": [
{
"campaign_id": "9b1f...c3",
"name": "2026-08-12 API campaign",
"status": "Completed",
"messages": 120,
"created_at": "2026-08-12T09:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 4,
"per_page": 25,
"total": 98
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List sender IDs
requires authentication
Your approved sender IDs. Only these can be used to send - anything else
is rejected with 404 Sender ID Not Found.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/senders',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/senders'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/senders',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/senders" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/sms/senders"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"sender_id": "MASOKO",
"is_default": true
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get campaign statistics
requires authentication
Delivery totals for one campaign.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/campaign/sms/statistics/86939523-bab7-40cf-8a9a-f57919c02980',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/campaign/sms/statistics/86939523-bab7-40cf-8a9a-f57919c02980'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/campaign/sms/statistics/86939523-bab7-40cf-8a9a-f57919c02980',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/campaign/sms/statistics/86939523-bab7-40cf-8a9a-f57919c02980" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/campaign/sms/statistics/86939523-bab7-40cf-8a9a-f57919c02980"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get a message delivery report
requires authentication
Delivery detail for a single message.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/report/bcf8534f-aa13-4a66-948e-d1e45c9b35bf',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/report/bcf8534f-aa13-4a66-948e-d1e45c9b35bf'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/report/bcf8534f-aa13-4a66-948e-d1e45c9b35bf',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/report/bcf8534f-aa13-4a66-948e-d1e45c9b35bf" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/sms/report/bcf8534f-aa13-4a66-948e-d1e45c9b35bf"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get delivery status for one recipient
requires authentication
Delivery status of a single recipient within a campaign.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/report/86939523-bab7-40cf-8a9a-f57919c02980/255700000000',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/report/86939523-bab7-40cf-8a9a-f57919c02980/255700000000'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/report/86939523-bab7-40cf-8a9a-f57919c02980/255700000000',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/report/86939523-bab7-40cf-8a9a-f57919c02980/255700000000" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/sms/report/86939523-bab7-40cf-8a9a-f57919c02980/255700000000"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Full delivery breakdown
requires authentication
Message counts broken down by delivery status, gender, age band and recipient location over a date range.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/sms/campaign/report/dates',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'start' => '2026-01-01',
'end' => '2026-12-31',
],
'json' => [
'start' => '2026-09-06T16:14:20',
'end' => '2026-09-06T16:14:20',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/sms/campaign/report/dates'
payload = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
}
params = {
'start': '2026-01-01',
'end': '2026-12-31',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()
require 'rest-client'
body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/sms/campaign/report/dates',
body ,
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/sms/campaign/report/dates?start=2026-01-01&end=2026-12-31" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"start\": \"2026-09-06T16:14:20\",
\"end\": \"2026-09-06T16:14:20\"
}"
const url = new URL(
"https://masokodigital.co.tz/api/sms/campaign/report/dates"
);
const params = {
"start": "2026-01-01",
"end": "2026-12-31",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"start": "2026-09-06T16:14:20",
"end": "2026-09-06T16:14:20"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Send WhatsApp messages, check your balance, and see which of your numbers and templates are cleared for use.
WhatsApp is stricter than SMS in two ways worth knowing before you integrate. You can only send from a number Meta has approved, and you can only open a conversation with a template Meta has approved - free-form text is accepted solely inside the 24-hour window that a customer's own message opens.
Send a WhatsApp message
requires authentication
Sends one message to one recipient and bills one credit.
Pass template to open a conversation; without it the message is
free-form and will only be delivered if the recipient has messaged you
within the last 24 hours. Omit sender to use your default number.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->post(
'https://masokodigital.co.tz/api/whatsapp/send',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'recipient' => '255700000000',
'message' => 'Hello Amina, your order 4471 has shipped.',
'template' => '9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22',
'sender' => '255700000002'."\n"
."\n"
.'The `status` returned is WhatsApp\'s acknowledgement, not proof of'."\n"
.'receipt. Poll `GET /api/whatsapp/message/{message_id}` to find out'."\n"
.'whether it was delivered and read.',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/whatsapp/send'
payload = {
"recipient": "255700000000",
"message": "Hello Amina, your order 4471 has shipped.",
"template": "9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22",
"sender": "255700000002\n\nThe `status` returned is WhatsApp's acknowledgement, not proof of\nreceipt. Poll `GET \/api\/whatsapp\/message\/{message_id}` to find out\nwhether it was delivered and read."
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('POST', url, headers=headers, json=payload)
response.json()
require 'rest-client'
body = {
"recipient": "255700000000",
"message": "Hello Amina, your order 4471 has shipped.",
"template": "9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22",
"sender": "255700000002\n\nThe `status` returned is WhatsApp's acknowledgement, not proof of\nreceipt. Poll `GET \/api\/whatsapp\/message\/{message_id}` to find out\nwhether it was delivered and read."
}
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.post(
'https://masokodigital.co.tz/api/whatsapp/send',
body ,
headers
)
p response.body
curl --request POST \
"https://masokodigital.co.tz/api/whatsapp/send" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"recipient\": \"255700000000\",
\"message\": \"Hello Amina, your order 4471 has shipped.\",
\"template\": \"9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22\",
\"sender\": \"255700000002\\n\\nThe `status` returned is WhatsApp\'s acknowledgement, not proof of\\nreceipt. Poll `GET \\/api\\/whatsapp\\/message\\/{message_id}` to find out\\nwhether it was delivered and read.\"
}"
const url = new URL(
"https://masokodigital.co.tz/api/whatsapp/send"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"recipient": "255700000000",
"message": "Hello Amina, your order 4471 has shipped.",
"template": "9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22",
"sender": "255700000002\n\nThe `status` returned is WhatsApp's acknowledgement, not proof of\nreceipt. Poll `GET \/api\/whatsapp\/message\/{message_id}` to find out\nwhether it was delivered and read."
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message_id": "9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c",
"status": "queued",
"to": "255700000000",
"from": "255700000002",
"balance": 411
}
Example response (400):
{
"error": {
"recipient": [
"The recipient field is required."
]
}
}
Example response (402):
{
"error": "You do not have enough WhatsApp credits. Please buy more."
}
Example response (404):
{
"error": "Template Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get WhatsApp balance
requires authentication
Remaining WhatsApp credits on your account. One credit is one message.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/whatsapp/balance',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/whatsapp/balance'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/whatsapp/balance',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/whatsapp/balance" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/whatsapp/balance"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"balance": 411
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List WhatsApp numbers
requires authentication
The numbers registered to your account and where each one stands.
Only a number with status approved can send.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/whatsapp/senders',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/whatsapp/senders'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/whatsapp/senders',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/whatsapp/senders" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/whatsapp/senders"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"number": "255700000002",
"display_name": "Masoko Digital",
"status": "approved",
"is_default": true
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List WhatsApp templates
requires authentication
Your templates and where each one stands. Only a template with status
approved can be used to open a conversation; the others are listed so
you can see what is still in review and why anything was turned down.
variables lists the placeholders in the body, in the order Meta
expects their values.
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/whatsapp/templates',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/whatsapp/templates'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/whatsapp/templates',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/whatsapp/templates" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/whatsapp/templates"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"template_id": "9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22",
"name": "Order Update",
"type": "utility",
"language": "en",
"body": "Hello 1, your order 2 has shipped.",
"variables": [
"1",
"2"
],
"status": "approved",
"rejection_reason": null
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get a message's delivery status
requires authentication
Where one message got to, and when.
status moves forward through queued, sent, delivered and read,
and never backwards - so a message that reads delivered has been
delivered even if a later callback says otherwise. failed and
undelivered are terminal, and carry the reason in error.
read depends on the recipient having read receipts switched on. When
they are off, a message that was read stops at delivered, so treat a
missing read_at as "not known" rather than "not read".
Example request:
$client = new \GuzzleHttp\Client();
$response = $client->get(
'https://masokodigital.co.tz/api/whatsapp/message/9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c',
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://masokodigital.co.tz/api/whatsapp/message/9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()
require 'rest-client'
headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
}
response = RestClient.get(
'https://masokodigital.co.tz/api/whatsapp/message/9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c',
headers
)
p response.body
curl --request GET \
--get "https://masokodigital.co.tz/api/whatsapp/message/9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://masokodigital.co.tz/api/whatsapp/message/9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"message_id": "9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c",
"status": "read",
"to": "255700000000",
"from": "255700000002",
"direction": "outbound",
"sent_at": "2026-09-06T09:00:00.000000Z",
"delivered_at": "2026-09-06T09:00:04.000000Z",
"read_at": "2026-09-06T09:12:31.000000Z",
"error": null
}
Example response (404):
{
"error": "Message Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.