Authentication & tokens
Every API call authenticates with a Bearer token in the Authorization header. Which kind of token you use depends on which part of the API you're calling.
The one header you always send
Authorization: Bearer YOUR_TOKENToken types
Which token where
| Field | Type | Required | Description |
|---|---|---|---|
| mbs_ scoped token | mbs_… | Yes | Created in the portal under API Tokens in the sidebar, with explicit scopes. Works on every endpoint in these docs: the /v1/ and /v2/ SMS routes and the /api/v1/ platform resources, provided it carries the matching scope (e.g. Send messages for the send endpoints). This is the token new integrations should use. Stored hashed on our side. Copy it when created; it is never shown again. |
| Legacy API token | opaque string | No | Pre-existing tokens issued by the old platform. Still fully supported on the frozen /v1/ and /v2/ endpoints. Existing integrations need no changes, but new ones can no longer be created. |
| JWT (session) | signed JWT | No | Issued when a user signs in to the portal. It is a browser session credential; don't build server integrations on it; use an mbs_ token instead. |
Where the token can go on /v1 and /v2
The frozen endpoints accept the credential in any of the places the old platform did, so an integration written years ago keeps working unchanged. All four are equivalent:
Authorization: Bearer <token>— preferred.?api_token=<token>in the query string.- An
api_tokenfield in a form-encoded or multipart body. - An
api_tokenkey in a JSON body.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
# Header (preferred)
curl "https://api.mobilesasa.com/v1/get-balance/" \
-H "Authorization: Bearer $MOBILESASA_TOKEN"
# Query string
curl "https://api.mobilesasa.com/v1/get-balance/?api_token=$MOBILESASA_TOKEN"
# Form field, alongside the payload
curl -X POST "https://api.mobilesasa.com/v1/send/message" \
-d "api_token=$MOBILESASA_TOKEN" \
-d "senderID=ACME" -d "phone=0712345678" -d "message=Hello"Prefer the header
Authorization header unless your platform genuinely cannot set one.Creating an mbs_ token with scopes
- Portal sidebar → API Tokens → New token.
- Pick the scopes the integration needs. Least privilege wins. A token that only sends WhatsApp templates can't touch your contacts.
- Optionally set an expiry. Copy the
mbs_…value once, store it in your secret manager.
What you can scope a token to
Every product on the platform is grantable, so a token can be as narrow as the job it does:
- Messages —
team:messages:send,team:messages:view - Campaigns —
create,send,view,cancel - Contacts & groups —
team:contacts:*,team:groups:* - Sender IDs — request, view, manage templates, view history, delete
- Blacklist — view, create, manage, delete
- WhatsApp —
send,view,manage - Surveys —
view,send,responses - USSD —
view,manage,menus - Shortcodes & keywords — view and manage each
- Inbound —
team:inbound:view - Email —
view,manage - Reminders —
view,manage - Exports —
view,request - Reports and API tokens —
view, andmanagefor tokens
Four things are deliberately not grantable to a token, no matter the role: team:settings:manage (money and account configuration), team deletion, and member invites or management. Those are decisions a signed-in human makes, not something an integration key should be able to do while nobody is watching.
Rotating and revoking
Tokens can be revoked instantly from the same portal page. Revocation takes effect within seconds across the platform. For zero-downtime rotation: create the new token, deploy it, then revoke the old one.
Common auth failures
401/responseCode 0401: missing, mistyped, expired or revoked token. Check for a stray newline or the wordBearerappearing twice.403: the token is valid but lacks the scope or permission for that endpoint.
Full response semantics live in Responses & errors.