Submit survey
Submit survey
Contents
- Overview
- Version-specific information
- Permissions and authentication
- HTTP parameters
- Answers
- Completing a survey only once
- Headers
- Response
- Possible error responses
- Sample request
Overview
- Call name: submit-survey
- Endpoint URL: https://{API hostname}/submit-survey
- Request methods: POST
- Request Content-Type: application/json
- Response Content-Type: application/json
- Auth required: yes
Completes a survey campaign for one shopper by submitting a set of answers, and issues the direct rewards configured on the campaign's reward methods.
The campaign_id must belong to a composable campaign with context set to survey. Any other campaign is rejected with
parameter_invalid.
The survey definition to answer can be retrieved with survey.
Version-specific information
The following version-specific changes apply to this endpoint. See the versioning page for more details.
| Version | Change details |
|---|---|
| >= 1.6.8 | This endpoint was added in this version |
Permissions and authentication
This API call requires a valid Spaaza session. The session can be as follows:
- User authentication: a session generated by an end-user login. The survey is completed for the logged-in shopper.
- Admin authentication: the performing user needs to be logged in and have
write accessto the chain of the campaign. - Privileged authentication: the use of privileged authentication is permitted for this endpoint.
The shopper and the campaign must belong to the same chain, otherwise entity_mismatch is returned.
The campaign's active segment restrictions are enforced again on submission, so a shopper who no longer matches the segment
cannot complete the survey and receives user_does_not_match_segment.
HTTP parameters
The following parameters can be passed to the API:
| Parameter | Description |
|---|---|
| campaign_id mandatory | (integer) The ID in Spaaza of the survey campaign. |
| answers mandatory | (array) The answers to the survey questions. See Answers. An answers value which is not an array is rejected with parameter_invalid. |
| chain_id optional | (integer) The ID of the chain. When omitted, the chain of the campaign is used. |
| user_id OR member_number OR authentication_point_identifier mandatory with admin or privileged authentication | The Spaaza unique ID (user_id), member_number (user code) or identity in a third-party authentication system (authentication_point_identifier) of the shopper for whom the survey is being completed. |
Answers
Each element of answers is an object identifying one active question and its value:
| Field | Description |
|---|---|
| question_key mandatory | (string) The key of an active question on the campaign. May also be sent as key. Each key may appear once. |
| value | The answer value. The accepted shape depends on the question type. |
The accepted value per question type, and the validation applied, are listed under
Survey question types. Required questions must be answered; optional
questions may be omitted. Answers referencing a question which is not active, duplicate question keys, and values which do
not match the question type are all rejected with parameter_invalid.
Required questions must be explicitly answered. For a required consent question, both boolean true and boolean false
count as answers; omitted, null, empty, and whitespace-only values do not. Optional unanswered questions can be omitted
from the answers array.
Completing a survey only once
A shopper can complete each survey campaign once. When the survey has already been completed, the endpoint returns the
existing response with already_completed set to true and does not store new answers or issue a further reward. Repeating
the same submission is therefore safe.
Requests for the same campaign and shopper are processed one at a time. A second request which arrives while the first is
still being processed is rejected with parallel_request_conflict, and can be retried.
Storing the response and issuing its rewards is atomic: if reward processing fails, the response is not stored, no reward is issued, and an error is returned.
Headers
The following headers can/must be passed to the API call:
| Parameter | Description |
|---|---|
| X-Spaaza-API-Version | (recommended) The API version, for example 1.6.8. |
| X-Spaaza-MyPrice-App-Hostname | (mandatory in the case of user authentication, not required otherwise) The hostname of the app for which the survey is being submitted. |
Response
| Field | Description |
|---|---|
| success | (boolean) true when the survey is completed. |
| already_completed | (boolean) true when the shopper had already completed this survey, in which case the existing response is returned unchanged. |
| survey_response | The stored survey response. |
| survey_response.id | (integer) The ID of the survey response. |
| survey_response.campaign_id | (integer) The ID of the survey campaign. |
| survey_response.user_id | (integer) The Spaaza ID of the shopper. |
| survey_response.member_number | (string) The member number (user code) of the shopper. |
| survey_response.status | (string) The status of the response, for example completed. |
| survey_response.definition_snapshot | The survey definition as it was when the shopper submitted the survey. |
| survey_response.reward_status | (string) issued, no_reward or pending. See Survey rewards and completion state. |
| survey_response.reward_summary | An object describing the rewards which were issued for the completed survey. |
| survey_response.completed_date | (string) The date and time the survey was completed. |
| survey_response.answers | (array) The stored answers, each with id, question_id, question_key, question_type, value, question_snapshot and option_snapshot. Answers belonging to deleted questions are omitted. |
Possible error responses
The following represents a list of possible error responses for the submit-survey endpoint:
| Code | Name and Description | HTTP Status Code |
|---|---|---|
| 6 | no_valid_session The user needs to be logged in and a valid session key needs to be sent | 401 |
| 68 | permission_denied_or_non_existent This user has insufficient permissions for this object or the object does not exist. | 403 |
| 154 | user_id_invalid The user_id passed must be an integer up to 10 digits long | 400 |
| 217 | chain_id_not_found No record has been found for that chain_id | 400 |
| 244 | campaign_id_invalid The campaign_id passed must be an integer | 400 |
| 245 | campaign_id_not_present The campaign_id must be passed as a parameter | 400 |
| 246 | campaign_id_not_found The campaign_id supplied could not be found | 404 |
| 270 | user_not_found No user was found | 404 |
| 405 | entity_mismatch The entities or chains supplied do not match | 400 |
| 419 | parameter_invalid One of the parameters is invalid and should be in a different format. Returned when the campaign is not a survey campaign, when answers is not an array, when an answer does not match an active question, and when an answer value does not satisfy its question type. | 400 |
| 505 | user_does_not_match_segment The user must be in the correct segment to perform this action | 400 |
| 552 | parallel_request_conflict Unable to process because another request for the same object is already in progress | 409 |
| 553 | call_processing_backend_unavailable Unable to process because the call-processing backend is currently unavailable | 503 |
Sample request
POST /submit-survey
{
"campaign_id": 300,
"answers": [
{ "question_key": "favourite_department", "value": "fresh" },
{ "question_key": "nps", "value": 9 }
]
}
An example response
{
"result": {
"code": 1,
"status": "ok"
},
"results": {
"success": true,
"already_completed": false,
"survey_response": {
"id": 501,
"campaign_id": 300,
"user_id": 90210,
"member_number": "1234567890",
"status": "completed",
"reward_status": "issued",
"reward_summary": {
"reward_status": "issued",
"rewards": []
},
"completed_date": "2026-08-17 11:04:22",
"answers": [
{
"id": 8801,
"question_id": 41,
"question_key": "favourite_department",
"question_type": "single_choice",
"value": "fresh",
"option_snapshot": [
{
"key": "fresh",
"label": "Fresh",
"value": "fresh"
}
]
}
]
}
}
}