Returns the individual submitted answers of a survey cycle. Required scope: r_surveys.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
This endpoint uses ther_surveysscope, which must be enabled through the Integrations section found within the Settings menu.
Requires a user token whose member has permission to view survey cycles, or an account token together with the member_id query parameter of such a member (the request is then evaluated with that member's permissions). An account token without member_id gets 403 Account tokens need a member_id for this operation. The account must have the Surveys feature enabled.
Only answers of submitted responses are returned, and empty answers are skipped. Members with a scoped role only receive answers of employees within their scope. Deleted survey cycles, and survey cycles outside a scoped member's scope, return 404.
Answers are ordered by participant last name, then first name, then answer id, so paging with limit / offset is stable.
Anonymity
The response shape depends on the survey's is_anonymous setting (see GET /surveys/:id):
- Non-anonymous surveys return each answer together with the participant's identity (
employee), the response it belongs to (employee_survey_id) and its submission time (submitted_at). - Anonymous surveys return the answer content only (
id,question_id,question_type,answer,choices). Participant identity,employee_survey_idandsubmitted_atare never included, so answers cannot be linked to a respondent or to each other.
In addition, when an anonymous survey has min_responses_required greater than 0:
- No answers are returned until at least
min_responses_requiredresponses have been submitted. - Once the threshold is met, answers are returned only for questions that have themselves received at least
min_responses_requiredanswers.
Withheld answers are still counted in total_count.
Pagination
limit defaults to 50 (maximum 200) and offset defaults to 0. total_count is the total number of answers matching the filters, regardless of limit / offset.
Use question_ids[] to restrict the answers to specific questions, e.g. ?question_ids[]=2501ee00-0004-51cc-8e1c-6b29548a3d01. Ids that do not belong to the survey's questionnaire are ignored; if none match, an empty result is returned.
Results
Non-anonymous survey:
{
"total_count": 3,
"answers": [
{
"id": "1b3f",
"employee_survey_id": "9c2",
"question_id": "2501ee00-0003-51cc-8e1c-6b29548a3d01",
"question_type": "paragraph",
"answer": "<p>Solving customer problems with the team.</p>",
"choices": null,
"submitted_at": "2025-03-02T10:05:00.000Z",
"employee": {
"id": "5e7",
"name": "Doe, Jane"
}
},
{
"id": "1b40",
"employee_survey_id": "9c2",
"question_id": "2501ee00-0004-51cc-8e1c-6b29548a3d01",
"question_type": "multiple_choice",
"answer": null,
"choices": [
"1"
],
"submitted_at": "2025-03-02T10:05:00.000Z",
"employee": {
"id": "5e7",
"name": "Doe, Jane"
}
},
{
"id": "1b3a",
"employee_survey_id": "9c5",
"question_id": "2501ee00-0004-51cc-8e1c-6b29548a3d01",
"question_type": "multiple_choice",
"answer": null,
"choices": [
"2"
],
"submitted_at": "2025-03-05T12:00:00.000Z",
"employee": {
"id": "5f1",
"name": "Smith, Alex"
}
}
]
}Anonymous survey:
{
"total_count": 2,
"answers": [
{
"id": "1b3f",
"question_id": "2501ee00-0003-51cc-8e1c-6b29548a3d01",
"question_type": "paragraph",
"answer": "<p>Solving customer problems with the team.</p>",
"choices": null
},
{
"id": "1b40",
"question_id": "2501ee00-0004-51cc-8e1c-6b29548a3d01",
"question_type": "multiple_choice",
"answer": null,
"choices": [
"1"
]
}
]
}| key | type | description |
|---|---|---|
| total_count | integer | Number of answers matching the filters, including answers withheld by the anonymity threshold |
| answers | array | Array of answer objects |
| answers[].id | string | Answer key |
| answers[].employee_survey_id | string | Key of the participant's response the answer belongs to. Non-anonymous surveys only |
| answers[].question_id | string | Question id (see the survey's template questionnaire) |
| answers[].question_type | string | Question type in snake_case. One of: paragraph, paragraph_star_rated, paragraph_numeric_rated, paragraph_custom_rated, single_choice, multiple_choice, star_rated, numeric_rated, custom_rated |
| answers[].answer | string | null | Free-text answer (HTML), if any |
| answers[].choices | array | null | Selected option / choice keys (strings), if any |
| answers[].submitted_at | string | null | ISO 8601 timestamp the response was submitted. Non-anonymous surveys only |
| answers[].employee | object | null | Participant who gave the answer. Non-anonymous surveys only |
| answers[].employee.id | string | Employee key |
| answers[].employee.name | string | Employee name, formatted as Last name, First name (preferred name is used when set) |
Error responses
| Status | Condition |
|---|---|
| 400 | id is not a valid survey cycle key, or invalid query parameters (limit outside 1–200, offset < 0, a question_ids[] value that is not a UUID) |
| 401 | Missing or invalid token |
| 403 | Missing r_surveys scope, account token without member_id, the Surveys feature is not enabled for the account, or the user lacks permission to view survey cycles |
| 404 | No survey cycle with the supplied id exists in the account, it is deleted, it is outside the member's scope, or its questionnaire template cannot be found |
Error bodies: 401 / 403 responses are plain text holding the reason (e.g. Required scopes missing: ["r_surveys"]). 404 responses are JSON of the form {"message": "..."}. 400 validation errors are JSON keyed by the offending field, e.g. {"limit": {"code": "number.min", "message": "\"limit\" must be greater than or equal to 1"}}.
