MENU navbar-image

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"
}
 

Request      

POST api/sms/send/single

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

sender_id   string   

An approved sender ID. Example: MASOKO

message   string   

The message body. Example: Hello from MasokoDigital

recipient   string   

Recipient MSISDN. Example: 255700000000

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"
}
 

Request      

POST api/sms/send/bulk

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

sender_id   string   

An approved sender ID. Example: MASOKO

message   string   

The message body. Example: Hello from MasokoDigital

recipients   string[]   

Recipient MSISDNs.

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
}
 

Request      

GET api/sms/balance

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

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
}
 

Request      

GET api/campaign/sms/report

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Query Parameters

start   string   

date Start of the range. Example: 2026-01-01

end   string  optional  

date End of the range. Example: 2026-12-31

Body Parameters

start   string   

Must be a valid date. Example: 2026-09-06T16:14:20

end   string  optional  

Must be a valid date. Example: 2026-09-06T16:14:20

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
    }
}
 

Request      

GET api/sms/campaigns

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Query Parameters

start   string  optional  

date Only campaigns created on or after this date. Example: 2026-01-01

end   string  optional  

date Only campaigns created on or before this date. Example: 2026-12-31

per_page   integer  optional  

Results per page, 1-200. Defaults to 25. Example: 50

Body Parameters

start   string  optional  

Must be a valid date. Example: 2026-09-06T16:14:20

end   string  optional  

Must be a valid date. Example: 2026-09-06T16:14:20

per_page   integer  optional  

Must be at least 1. Must not be greater than 200. Example: 21

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
        }
    ]
}
 

Request      

GET api/sms/senders

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

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());

Request      

GET api/campaign/sms/statistics/{campaign_scuuid}

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

campaign_scuuid   string   

Example: 86939523-bab7-40cf-8a9a-f57919c02980

campaign   string   

The campaign_id returned when sending. Example: 9b1f...c3

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());

Request      

GET api/sms/report/{sms_smsuuid}

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

sms_smsuuid   string   

Example: bcf8534f-aa13-4a66-948e-d1e45c9b35bf

sms   string   

The message identifier. Example: 9c2a...f1

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());

Request      

GET api/sms/report/{campaign_scuuid}/{phone}

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

campaign_scuuid   string   

Example: 86939523-bab7-40cf-8a9a-f57919c02980

phone   string   

Recipient MSISDN. Example: 255700000000

campaign   string   

The campaign_id returned when sending. Example: 9b1f...c3

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());

Request      

GET api/sms/campaign/report/dates

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Query Parameters

start   string   

date Start of the range. Example: 2026-01-01

end   string  optional  

date End of the range. Example: 2026-12-31

Body Parameters

start   string   

Must be a valid date. Example: 2026-09-06T16:14:20

end   string  optional  

Must be a valid date. Example: 2026-09-06T16:14:20

WhatsApp

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"
}
 

Request      

POST api/whatsapp/send

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

Body Parameters

recipient   string   

Recipient MSISDN in E.164, with or without the plus. Example: 255700000000

message   string   

The message body. Where a template is used, this is the text as the recipient should see it. Example: Hello Amina, your order 4471 has shipped.

template   string  optional  

An approved template id, from GET /api/whatsapp/templates. Required to start a new conversation. Example: 9c2f4e10-77a1-4a0e-9a1d-2f3f9d0f1b22

sender   string  optional  

One of your approved numbers. Defaults to your default number. Example: `255700000002

The status returned is WhatsApp's acknowledgement, not proof of receipt. Poll GET /api/whatsapp/message/{message_id} to find out whether it was delivered and read.`

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
}
 

Request      

GET api/whatsapp/balance

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

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
        }
    ]
}
 

Request      

GET api/whatsapp/senders

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

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
        }
    ]
}
 

Request      

GET api/whatsapp/templates

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

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"
}
 

Request      

GET api/whatsapp/message/{message}

Headers

Authorization      

Example: Bearer {YOUR_AUTH_KEY}

Content-Type      

Example: application/json

Accept      

Example: application/json

URL Parameters

message   string   

The message_id returned when sending. Example: 9b1f8c22-0b5e-4b1a-9a3a-1d2e3f4a5b6c