USSD codes & extensions
Two ways onto the dial pad: apply for your own dedicated code, or take an extension on a shared code (*657*45#) and be live in days instead of weeks.
Endpoints live under /api/v1/ with a scoped mbs_ token or JWT. Once a code or extension is approved, you decide how sessions are answered. A hosted menu, a survey, or callback mode against your own backend.
Fees
Approval checks your wallet, and fails if it can't pay
Short-term rentals
An extension does not have to be a monthly commitment. Pass rental_days (1–90) on the request and the extension becomes a fixed-term rental: you pay a pro-rata share of the monthly fee upfront (monthly × days ÷ 30, rounded up, VAT inclusive), it goes live on approval, and it simply expires at the end of the term — no auto-renewal, no further charges. Built for POCs, demos and one-day events; a one-day rental of a 4-digit extension costs a thirtieth of the month.
Option A: extension on a shared code
List the platform's shared codes, then check whether the extension you want is free:
{
"success": true,
"data": [
{ "uuid": "6a77e0b2-…", "code": "657", "networks": ["safaricom", "airtel", "telkom"] }
]
}# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl "https://api.mobilesasa.com/api/v1/ussd/shared-codes/6a77e0b2-…/availability?extension=45" \
-H "Authorization: Bearer $MOBILESASA_TOKEN"Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| ussd_code_id | uuid | Yes | UUID of the shared code (from the listing above). |
| extension | string | Yes | The digits after the star. Customers dial *657*45# for extension 45. 1–2 digit extensions cost more than longer ones. |
| networks | string[] | Yes | Networks the extension must answer on. |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/ussd/extensions \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ussd_code_id": "6a77e0b2-…",
"extension": "45",
"networks": [
"safaricom",
"airtel"
]
}'Option B: dedicated code
A dedicated code (*728#) is registered with the networks in your name. Expect network paperwork and a longer lead time. Send JSON for a bare application, or multipart/form-data when attaching supporting documents (authorisation letters, business certificate. 10 MB max per file; the file field name becomes the document type, with an optional network_{field} form value scoping it to one network).
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/ussd/codes \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-F "code=*728#" \
-F "networks=safaricom" \
-F "networks=airtel" \
-F "[email protected]" \
-F "network_request_letter=safaricom"JSON mode works too when there are no documents: {"code": "*728#", "networks": ["safaricom","airtel"]}.
Track the application
Both codes and extensions carry an approval_status (pending → approved | rejected, with rejection_reason on rejects. You're also emailed automatically either way) and a runtime status once live.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl "https://api.mobilesasa.com/api/v1/ussd/extensions/91c2f7aa-…" \
-H "Authorization: Bearer $MOBILESASA_TOKEN"Renewing before it expires
An extension carries an end_date. It renews itself from your KES wallet a month at a time, and you are warned three days ahead — but you can renew early, for as many months as you like, and see the price first.
{
"months": 3,
"monthly_fee": 5000,
"total": 15000,
"wallet_balance": 8000,
"shortfall": 7000,
"sufficient": false,
"new_end_date": "2026-11-21"
}The quote is the honest one: it says what you have, what it costs, and what is missing, before anything is charged. If the wallet is short, top it up (M-Pesa or card — see Top up via M-Pesa) and post the renewal. Renewing never shortens an expiry: months are added to whichever is later, today or the current end date.
Point it somewhere
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| mode | string | No | menu (hosted menu), survey, or callback (your backend drives every screen, see callback mode). |
| menu_id | uuid | No | The approved menu to serve, when mode is menu. |
| survey_id | uuid | No | The survey to run, when mode is survey. |
| callback_url | string | No | Your HTTPS endpoint, when mode is callback. |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X PUT https://api.mobilesasa.com/api/v1/ussd/extensions/91c2f7aa-… \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mode": "callback",
"callback_url": "https://example.com/ussd"
}'