Surveys
Multi-question SMS conversations: a customer texts your keyword, gets asked each question in turn, and every answer is stored for you to pull over the API. No app, no data bundle needed on the customer's side.
A survey attaches to a keyword , every inbound text matching that keyword opens a survey session. The same survey engine also powers USSD survey mode. Endpoints live under /api/v1/ with a scoped mbs_ token or JWT.
Create a survey
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Internal label. |
| keyword_uuid | uuid | Yes | The approved keyword that triggers this survey. |
| sender_name | string | Yes | Sender the questions go out under, usually the shortcode itself. |
| welcome_message | string | Yes | Sent once when a session starts, before the first question. |
| end_message | string | Yes | Sent after the last answer. Thank-yous, vouchers, next steps. |
| session_timeout_minutes | int | No | How long to wait for an answer before the session is marked abandoned. |
| questions | Question[] | No | The questions, inline, or add them one at a time afterwards (below). |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/surveys \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Delivery satisfaction. July",
"keyword_uuid": "8c11d2ab-…",
"sender_name": "40404",
"welcome_message": "Thanks for ordering from Dukapay! 3 quick questions:",
"end_message": "Asante! Your feedback keeps us sharp.",
"session_timeout_minutes": 30,
"questions": [
{
"question": "How would you rate your delivery? Reply 1-5",
"question_type": "numeric",
"sequence": 1,
"is_required": true
},
{
"question": "Was the rider courteous? Reply YES or NO",
"question_type": "yes_no",
"sequence": 2,
"is_required": true
},
{
"question": "Anything we should improve?",
"question_type": "open",
"sequence": 3,
"is_required": false
}
]
}'Add questions
Question fields
| Field | Type | Required | Description |
|---|---|---|---|
| question | string | Yes | The text sent to the participant. |
| question_type | string | Yes | open (free text), single_choice, multiple_choice, numeric, yes_no. |
| options | JSON string | No | For choice types: the options as a JSON array string, e.g. "[\"M-Pesa\",\"Card\",\"Cash\"]". Participants reply with the option number. |
| sequence | int | Yes | Order the question is asked in (1-based). |
| is_required | boolean | No | Required questions re-prompt on an invalid answer; optional ones accept SKIP. |
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/surveys/5e9dd410-…/questions \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"question": "How did you pay? 1. M-Pesa 2. Card 3. Cash",
"question_type": "single_choice",
"options": "[\"M-Pesa\",\"Card\",\"Cash\"]",
"sequence": 4,
"is_required": true
}'Lifecycle
Statuses
| Field | Type | Required | Description |
|---|---|---|---|
| draft | initial | No | Editable (PATCH); not answering traffic. A survey needs at least one question, and no pending system approval, before it can activate. |
| active | live | No | Keyword texts open sessions and questions flow. |
| paused | hold | No | New sessions refused; re-activate any time. |
| closed | final | No | Done. Data remains available. |
Approval on amendments
POST /surveys/{uuid}/amend with starts_at/ends_at) puts it through a quick system review; the survey can't activate while that review is pending. You're emailed automatically when it's approved or rejected.Test it before going live
The simulator walks a fake session without sending real SMS. Post the participant's next reply, get back what the survey would send:
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/surveys/5e9dd410-…/simulate \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"msisdn": "254712345678",
"message": "START"
}'You can also restrict a live survey to test numbers with the whitelist (PUT /surveys/{uuid}/whitelist with {"msisdns": ["2547…"]}; empty array lifts the restriction).
Start a survey yourself
A survey usually waits to be texted. This makes it speak first: give it a number and it opens the session and sends question one, from the shortcode its keyword sits on. The reply comes back the ordinary way, so the conversation continues exactly as if the person had texted the keyword themselves.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/surveys/5e9dd410-…/start \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"msisdn": "254712345678"
}'{
"success": true,
"data": { "status": "sent", "msisdn": "254712345678" }
}Requirements
| Field | Type | Required | Description |
|---|---|---|---|
| Scope | team:surveys:send | No | The API token needs it. Create one under Settings → API tokens. |
| Status | active | No | A draft or paused survey is refused: activate it first. |
| Keyword | required | No | The survey's keyword decides which shortcode the question is sent from, and where the answer comes back to. A survey with no keyword has nowhere to send from. |
| Balance | units | No | Question one is a billed SMS like any other, and so is every question after it. |
Where this earns its keep
USSD surveys cannot be started this way
Send it to a whole group
One number at a time is the API; a list is a campaign. Create a campaign with survey_uuidset and every recipient is put into a session as their message goes out — priced, reserved and cancellable like any other campaign, and listed with the rest. The survey's own shortcode is used as the sender whatever you pass, because a question asked from another identity has nowhere to be answered.
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl -X POST https://api.mobilesasa.com/api/v1/campaigns \
-H "Authorization: Bearer $MOBILESASA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer satisfaction",
"message": "Two quick questions.\nHow did we do?\n1. Yes\n2. No",
"source_type": "groups",
"target_group_uuids": [
"9f31…"
],
"survey_uuid": "5e9dd410-…"
}'The portal does this for you
Pull the responses
# Paste your token once (it starts with mbs_):
export MOBILESASA_TOKEN="mbs_your_token_here"
curl "https://api.mobilesasa.com/api/v1/surveys/5e9dd410-…/responses?page=1" \
-H "Authorization: Bearer $MOBILESASA_TOKEN"{
"success": true,
"data": [
{
"uuid": "77b0…",
"session_uuid": "d2c4…",
"msisdn": "254712345678",
"question_uuid": "31aa…",
"answer": "5",
"created_at": "2026-07-11T12:40:19Z"
}
],
"meta": { "page": 1, "page_size": 20, "total": 412 }
}Answers cost units