Top up your wallet and SMS units
Your account has two balances: SMS units, which every message spends, and a KES wallet for fees. You can fund either one over the API or from the M-Pesa menu, and move money from the wallet into units whenever you like.
SMS units are sending credit: one unit per SMS part, bought at your account's rate. The wallet holds KES for one-time and service fees such as sender ID registrations, shortcode deposits and USSD fees, and it can be converted into units at any time. Both balances come back from GET /api/v1/units/balance.
Token scope
mbs_ API token, every call on this page needs the team:wallet:topup scope; a token without it gets a 403. See Authentication. Signed-in portal users are not affected.Which route to use
- Automated top-ups: keep the wallet funded, then buy units from it when your balance runs low. One API call, no payer involved. See wallet to SMS units.
- Buy units directly: send an M-Pesa prompt for units, or pay the paybill with your plain account number.
- Fund the wallet: send an M-Pesa prompt for the wallet, or pay the paybill with
wl-in front of your account number.
Wallet to SMS units
Converts wallet KES into SMS units at your account's rate, in one step and immediately. This is the call to automate: check your unit balance on a schedule and buy more when it drops below your threshold.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| units | integer | Yes | How many SMS units to buy. The cost is units × your SMS rate, taken from the wallet. |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/units/purchase \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"units": 10000
}'{
"success": true,
"data": {
"units": 10000,
"cost_kes": 4000.00,
"sms_rate": 0.40,
"sms_balance": 25430,
"wallet_balance": 1200.00
}
}sms_balance and wallet_balance are the new balances after the purchase, so you do not need a second call to check them.
{
"success": false,
"error": "Insufficient balance to complete this action."
}A simple top-up loop
sms_balance from GET /api/v1/units/balance. When it falls below your floor, call POST /api/v1/units/purchase. If that returns 402, fund the wallet with an M-Pesa prompt (below) and try again once the deposit lands.Buy SMS units with M-Pesa
Sends an M-Pesa PIN prompt to the payer. When they approve it, the payment becomes SMS units at your rate: the amount divided by your SMS rate, rounded down.
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| phone | string | Yes | The Safaricom number to charge. The payer gets the PIN prompt on this phone. Any accepted format. |
| amount | number | Yes | KES amount, 1 to 250,000 (the M-Pesa per-transaction ceiling). |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/units/stk-push \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone": "0712345678",
"amount": 5000
}'{
"success": true,
"data": { "message": "STK push sent. Check your phone to complete payment." }
}Fund the wallet with M-Pesa
Same request and response as the units prompt; the payment lands in the KES wallet instead.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/wallet/stk-push \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone": "0712345678",
"amount": 5000
}'Credits are asynchronous
Pay from the M-Pesa menu (paybill)
Anyone can top up from their phone, no API involved. The account reference decides which balance the money goes to:
Paybill 4078003
| Field | Type | Required | Description |
|---|---|---|---|
| Account: your account number | SMS units | No | Your team's local_account_no, exactly as GET /api/v1/units/balance returns it. The payment becomes SMS units at your rate. |
| Account: wl- + your account number | KES wallet | No | For example wl- followed by your account number. The payment goes to the wallet. |
Check the account reference
wl- in front. Either way the money stays on your account, and you can always convert wallet to units with POST /api/v1/units/purchase.Confirming a top-up
Each balance has its own ledger. Match on the M-Pesa receipt number:
- SMS units: GET /api/v1/units/ledger. Units bought by M-Pesa or from the wallet appear as
purchaseentries. - Wallet: GET /api/v1/units/wallet/ledger. M-Pesa deposits appear as
deposit, conversions into units aspurchase.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl "https://api.mobilesasa.com/api/v1/units/wallet/ledger?page=1&page_size=10" \
-H "Authorization: Bearer $MOBILESASA_TOKEN"{
"success": true,
"data": [
{
"uuid": "f302…",
"entry_type": "deposit",
"amount": 5000.00,
"description": "M-Pesa deposit",
"mpesa_receipt": "SGH8KL2M9Q",
"created_at": "2026-07-11T14:03:51Z"
}
],
"meta": { "page": 1, "page_size": 10, "total": 1 }
}