Introduction
Main API endpoint
https://api.surveyhero.com/v1/
The SurveyHero API is REST-based and can be accessed with the use of API keys. Responses will always be in JSON format. This documentation will guide you through authentication and present all different endpoints that can be consumed.
Authentication
Creating API keys
Before you can start using the API, you will need to create a secret API key. To do this, please visit the "Developer API" section in your SurveyHero account.
Your API key will provide you with a username
and a password
. These credentials are required to perform "Basic Authentication" and obtain access to your data via this API.
Throughout this documentation we will show code examples containing username:password
. Please always replace username
and password
with your actual credentials.
Managing API keys
You can create multiple API keys and name them individually. This allows you to use one key per service, e.g. one key for your WordPress plugin and one for your cronjob server. In case of a compromise of one of those services, you will be able to only deactivate or delete the affected key, without disrupting your remaining services.
You can deactivate or delete an API key at any time in your account. API access to your data will be revoked immediately. The difference between "deactivating" and "deleting" is that deleting is permanent while a deactivated key can be reactivated.
How to authenticate
Example request
# Make sure to replace 'username' and 'password' with your actual credentials
curl "https://api.surveyhero.com/v1/" \
-u "username:password"
Authentication is done via "Basic Auth" (HTTP authentication), that requires a username
and a password
. The credentials are concatenated with a trailing colon (username:password
) and then encoded using a Base64 algorithm. This encoded value (e.g. dXNlcm5hbWU6cGFzc3dvcmQ=
) is then added to the request header:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Most programming languages and libraries provide built-in "Basic Auth" support that does automatically add the request header above. We recommend that you check first whether such an implementation already exists, before implementing your own.
Good To Know
Responses
Example response
{
"surveys": []
}
All responses are UTF-8 encoded and in JSON format. Responses will always return an object literal as main object, and never simply an array or a boolean, etc.
Timestamp
Example timestamp format
{
"created_on": "2017-08-07T12:07:56+00:00"
}
All timestamps are formatted based on ISO 8601. All timestamps are shown in UTC.
Rate Limiting
Please do not make more than two requests per second. Making a new request less than 500ms after the last request will immediately fail and return a "Too Many Requests" error.
Survey API
Get all surveys
Example request
curl "https://api.surveyhero.com/v1/surveys" \
-u "username:password"
Example response
{
"surveys": [
{
"survey_id": 1000,
"title": "Customer Satisfaction Survey",
"internal_name": "Long time customers",
"created_on": "2017-08-07T12:07:56+00:00",
"number_of_questions": 12,
"number_of_collectors": 2,
"number_of_responses": 78
},
{
"survey_id": 53635,
"title": "Event Feedback",
"internal_name": "",
"created_on": "2018-02-27T20:12:33+00:00",
"number_of_questions": 3,
"number_of_collectors": 1,
"number_of_responses": 2
}
]
}
This endpoint returns all surveys that you have access to. These are your own surveys as well as surveys shared with you from team members.
HTTP request
GET https://api.surveyhero.com/v1/surveys
Response properties
Property surveys
will contain an array with your surveys, sorted by survey title in alphabetical order.
Property | Type | Description |
---|---|---|
survey_id |
integer | Unique identifier for the survey. |
title |
string | Title of the survey. |
internal_name |
string | Private description of survey. Not visible to participants. |
created_on |
timestamp | Timestamp of when the survey was created. |
number_of_questions |
integer | Number of questions contained in survey. This does only contain actual questions, not static text or other elements. |
number_of_collectors |
integer | Number of collectors linked to this survey. |
number_of_responses |
integer | Total number of responses collected with survey. |
Get survey details
Example request
curl "https://api.surveyhero.com/v1/surveys/1001" \
-u "username:password"
Example response
{
"survey_id": 53635,
"title": "Event Feedback",
"internal_name": "",
"created_on": "2018-02-27T20:12:33+00:00",
"number_of_elements": 6,
"number_of_questions": 3,
"number_of_collectors": 1,
"number_of_responses": 2,
"number_of_webhooks": 1,
"settings": {
"is_anonymous": false
}
}
You can get more general details about a survey. This endpoint is normally the entry point for accessing its questions, responses, etc.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}
Response properties
The object will contain the same properties as in the survey overview, with following addition:
Property | Type | Description |
---|---|---|
number_of_elements |
integer | Total number of elements contained in the survey. This includes all questions as well as static elements, such as text, images, etc. |
number_of_webhooks |
integer | Total number of webhooks that have been set for this survey. |
settings.is_anonymous |
boolean | Whether it is an anonymous survey. |
Element API
Get all elements from survey
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/elements" \
-u "username:password"
Example response
{
"elements": [
{
"element_id": 664789,
"type": "text",
"text": {
"value": "Event Feedback",
"style": "header"
}
},
{
"element_id": 664697,
"type": "question",
"question": {
"question_text": "How likely is it that you would recommend the event to a friend or colleague?",
"description_text": "",
"type": "rating_scale",
"rating_scale": {
"style": "net_promoter_score",
"left": {
"label": "Not at all likely",
"value": 0
},
"right": {
"label": "Extremely likely",
"value": 10
},
"step_size": 1
},
"settings": {
"is_required": false
}
}
},
{
"element_id": 664706,
"type": "question",
"question": {
"question_text": "Is there anything you would like to share about the event?",
"description_text": "",
"type": "input",
"input": {
"default_value": "",
"placeholder_value": "",
"accepts": {
"type": "text",
"text": {
"max_number_of_characters": null
}
}
},
"settings": {
"is_required": false
}
}
}
]
}
As well as a variety of question types, a survey may also contain "helper" content such as text paragraphs, titles, images, etc. The overall term for all these is "elements". An element can therefore be a question or just static content. This endpoint will return all elements from your survey.
If you are only interested in the actual questions within your survey, you can also fetch questions only.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/elements
Response properties
Property elements
will contain an array with all elements contained in the survey. They are ordered according to their position in the live survey. While each element type will have specific properties, they do all share following properties:
Property | Type | Description |
---|---|---|
element_id |
integer | Unique identifier for the element. |
type |
string | Element type name. Each element type has different properties. |
Additionally, the element object will have a property named after its type. E.g. an element of type question
will also have a property called question
.
Get only questions from survey
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/questions" \
-u "username:password"
Example response
{
"elements": [
{
"element_id": 664697,
"type": "question",
"question": {
"question_text": "How likely is it that you would recommend the event to a friend or colleague?",
"description_text": "",
"type": "rating_scale",
"rating_scale": {
"style": "net_promoter_score",
"left": {
"label": "Not at all likely",
"value": 0
},
"right": {
"label": "Extremely likely",
"value": 10
},
"step_size": 1
},
"settings": {
"is_required": false
}
}
},
{
"element_id": 664706,
"type": "question",
"question": {
"question_text": "Is there anything you would like to share about the event?",
"description_text": "",
"type": "input",
"input": {
"default_value": "",
"placeholder_value": "",
"accepts": {
"type": "text",
"text": {
"max_number_of_characters": null
}
}
},
"settings": {
"is_required": false
}
}
}
]
}
Compared to fetching all elements, this endpoint will only return the question elements contained in the survey. Knowing the details about the questions within your survey will help you to understand the answer data from your respondents.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/questions
Response properties
Property elements
will contain an array with all questions contained in the survey, in the same order as they appear in the questionnaire. While each question type will have specific properties, all questions share following properties:
Property | Type | Description |
---|---|---|
question.question_text |
string | Question text. |
question.description_text |
string | Additional text below question text. |
question.settings |
object | Various properties based on question type. |
question.settings.is_required |
boolean | This setting is shared among all question types. If true , a participant cannot submit their answers without answering this question. |
Get data in specific language
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/elements?lang=de" \
-u "username:password"
If you have a multilingual survey, you may want to retrieve your survey's elements (or questions) in a specific language. To do that, simply add the required language as GET parameter to the endpoint. You can find all available languages for your survey with the Language API.
When no lang
parameter is provided, the data will be returned using the survey's main language.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/elements?lang={language_code}
Element Types
Every element object has at least three properties: element_id
, type
and a third property named like its type
. For example, if an element is of type text
, then there will also be a property named text
.
Currently, following element types exist: text
, image
, code
, separator
and question
text
element
Example
text
element
{
"element_id": 666755,
"type": "text",
"text": {
"value": "Customer Satisfaction Survey",
"style": "header"
}
}
Property | Type | Description |
---|---|---|
text.value |
string | The actual text content of the element. |
text.style |
string | The styling of the text content. Currently available: header or regular |
image
element
Example
image
element
{
"element_id": 667014,
"type": "image",
"image": {
"text": "Punta Espinosa, Galapagos",
"image_url": "https://d2f1nx482ui1xj.cloudfront.net/667014-96653577dcfc6eff2a57fcfb4c2bb843.jpg"
}
}
Property | Type | Description |
---|---|---|
image.text |
string | Text description of image, shown above the image. |
image.image_url |
string|null | URL path to image visible to the participant. null if no image was uploaded yet. |
code
element
Example
code
element
{
"element_id": 3314501,
"type": "code",
"code": "<iframe src=\"https://www.youtube.com/embed/dkPLIw9aZwY\" height=\"500\" width=\"100%\" frameborder=\"0\" allowfullscreen></iframe>"
}
Property | Type | Description |
---|---|---|
code |
string|null | Contains the actual embed code (iframe) or null if no code was defined yet. |
separator
element
Example
separator
element
{
"element_id": 666757,
"type": "separator",
"separator": {}
}
Property | Type | Description |
---|---|---|
separator |
object | Object containing all details of separator element (currently empty). |
question
element
Example
question
element
{
"element_id": 666812,
"type": "question",
"question": {
"question_text": "Do you have any further comments?",
"description_text": "Please feel free to leave us a note here.",
"type": "input",
"input": {
"default_value": "",
"placeholder_value": "",
"accepts": {
"type": "text",
"text": {
"max_number_of_characters": 500
}
}
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
question.question_text |
string | Question text. |
question.description_text |
string | Additional description text below question text. |
question.type |
string | Question type name. The question object will have an additional property named after its type. All different question types are described below. |
Question Types
Every question object has at least four properties: question_text
, description_text
, type
and a fourth property named like its type
. For example, if a question is of type input
, then there will also be a property named input
.
Currently, following question types exist: choice_list
, choice_table
, file_upload
, image_choice_list
, input
, input_list
, input_table
, ranking
and rating_scale
choice_list
question
Example
choice_list
question
{
"element_id": 666967,
"type": "question",
"question": {
"question_text": "Which of these courses have you already attended?",
"description_text": "You can select multiple options.",
"type": "choice_list",
"choice_list": {
"choices": [
{
"choice_id": 1745870,
"label": "Course A"
},
{
"choice_id": 1745871,
"label": "Course B"
},
{
"choice_id": 1745872,
"label": "Course C"
},
{
"choice_id": 1745873,
"label": "Course D"
},
{
"choice_id": 0,
"label": "Other"
}
],
"settings": {
"allows_multiple_choices": true,
"min_number_of_choices": null,
"max_number_of_choices": null
}
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
choice_list.choices |
object[] | Array of choice objects. |
choice_list.settings |
object | Object containing all available settings for this question type. |
choice_list.settings.allows_multiple_choices |
boolean | Whether participant can select multiple choices or only a single one. |
choice_list.settings.min_number_of_choices |
integer|null | Minimum number of choices that need to be selected. null if there are no restrictions. |
choice_list.settings.max_number_of_choices |
integer|null | Maximum number of choices that can be selected. null if there are no restrictions. |
choice_table
question
Example
choice_table
question
{
"element_id": 666978,
"type": "question",
"question": {
"question_text": "On which days do you use following products:",
"description_text": "You can select multiple options per row.",
"type": "choice_table",
"choice_table": {
"rows": [
{
"row_id": 1745892,
"label": "Product A"
},
{
"row_id": 1745893,
"label": "Product B"
},
{
"row_id": 1745894,
"label": "Product C"
}
],
"choices": [
{
"choice_id": 177294,
"label": "Mon"
},
{
"choice_id": 177295,
"label": "Tue"
},
{
"choice_id": 177296,
"label": "Wed"
},
{
"choice_id": 177297,
"label": "Thu"
},
{
"choice_id": 177298,
"label": "Fri"
}
],
"settings": {
"allows_multiple_choices_per_row": true
}
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
choice_table.rows |
object[] | Array of row objects. |
choice_table.choices |
object[] | Array of choice objects. |
choice_table.settings.allows_multiple_choices_per_row |
boolean | Whether a participant can select multiple choices per row or only a single one. |
file_upload
question
Example
file_upload
question
{
"element_id": 1387752,
"type": "question",
"question": {
"question_text": "Please upload your image here:",
"description_text": "",
"type": "file_upload",
"file_upload": {
"max_file_size_in_mb": 25,
"accepted_file_types": [
"gif",
"jpg",
"jpeg",
"png"
]
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
file_upload.max_file_size_in_mb |
integer | Maximum allowed file size in megabytes per uploaded file. |
file_upload.accepted_file_types |
string[] | Array of allowed file extensions (without leading dot/period) for uploaded files. |
image_choice_list
question
Example
image_choice_list
question
{
"element_id": 666941,
"type": "question",
"question": {
"question_text": "Please pick your two favorite images:",
"description_text": "You need to pick exactly 2 choices.",
"type": "image_choice_list",
"image_choice_list": {
"choices": [
{
"choice_id": 6244,
"label": "Beach",
"image_url": "https://s3-eu-west-1.amazonaws.com/surveyhero-image-choice/666941-6244-e1d86fa737d1bdfdc97aca8b172391e6.jpg"
},
{
"choice_id": 6245,
"label": "Woods",
"image_url": "https://s3-eu-west-1.amazonaws.com/surveyhero-image-choice/666941-6245-45848a2f16010e8bb1f0a0d2c8b8ba45.jpg"
},
{
"choice_id": 6246,
"label": "Mountains",
"image_url": "https://s3-eu-west-1.amazonaws.com/surveyhero-image-choice/666941-6246-c3597578a5b0894bb38603fa799cda18.jpg"
}
],
"settings": {
"allows_multiple_choices": true,
"min_number_of_choices": 2,
"max_number_of_choices": 2
}
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
image_choice_list.choices |
object[] | Array of "image choice" objects. |
image_choice_list.settings.allows_multiple_choices |
boolean | Whether participant can select multiple choices or only a single one. |
image_choice_list.settings.min_number_of_choices |
integer|null | Minimum number of choices that need to be selected. null if there are no restrictions. |
image_choice_list.settings.max_number_of_choices |
integer|null | Maximum number of choices that can be selected. null if there are no restrictions. |
input
question
Example
input
question
{
"element_id": 666811,
"type": "question",
"question": {
"question_text": "What is your full name?",
"description_text": "",
"type": "input",
"input": {
"default_value": "",
"placeholder_value": "",
"accepts": {
"type": "text",
"text": {
"max_number_of_characters": null
}
}
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
input.default_value |
string | Default value in the input field. |
input.placeholder_value |
string | Placeholder that is shown in the input field if no value is set. |
input.accepts |
object | Object that defines what values the input accepts. |
input_list
question
Example
input_list
question
{
"element_id": 667012,
"type": "question",
"question": {
"question_text": "Please enter your contact details:",
"description_text": "",
"type": "input_list",
"input_list": {
"accepts": {
"type": "text",
"text": {
"max_number_of_characters": null
}
},
"inputs": [
{
"input_id": 1745983,
"label": "First and last name"
},
{
"input_id": 1745984,
"label": "Street address"
},
{
"input_id": 1745985,
"label": "Postal code and city"
},
{
"input_id": 1745986,
"label": "Phone number"
},
{
"input_id": 1745987,
"label": "Email address"
}
]
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
input_list.accepts |
object | Object that defines what values the inputs accept. |
input_list.inputs |
object[] | Array of input objects. Each input inherits the above "accepts" behavior. |
input_table
question
Example
input_table
question
{
"element_id": 666981,
"type": "question",
"question": {
"question_text": "How many hours per day do you use following products:",
"description_text": "Please only enter numbers.",
"type": "input_table",
"input_table": {
"accepts": {
"type": "number",
"number": {}
},
"rows": [
{
"row_id": 1745901,
"label": "Product A"
},
{
"row_id": 1745902,
"label": "Product B"
},
{
"row_id": 1745903,
"label": "Product C"
}
],
"columns": [
{
"column_id": 177301,
"label": "Mon"
},
{
"column_id": 177302,
"label": "Tue"
},
{
"column_id": 177303,
"label": "Wed"
},
{
"column_id": 177304,
"label": "Thu"
},
{
"column_id": 177305,
"label": "Fri"
}
]
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
input_table.text |
object | Object that defines what values the inputs accept. |
input_table.rows |
object[] | Array of row objects. |
input_table.columns |
object[] | Array of column objects. |
ranking
question
Example
ranking
question
{
"element_id": 1238491,
"type": "question",
"question": {
"question_text": "Please rank the following in order of importance to you, first being the most important:",
"description_text": "",
"type": "ranking",
"ranking": {
"choices": [
{
"choice_id": 3132165,
"label": "Health"
},
{
"choice_id": 3132166,
"label": "Family & Friends"
},
{
"choice_id": 3132167,
"label": "Purpose"
},
{
"choice_id": 3132168,
"label": "Freedom"
},
{
"choice_id": 3132169,
"label": "Money"
}
],
"settings": {
"allows_not_applicable": true,
"not_applicable_label": "n/a"
}
},
"settings": {
"is_required": true
}
}
}
Property | Type | Description |
---|---|---|
ranking.choices |
object[] | Array of choice objects. |
ranking.settings.allows_not_applicable |
boolean | Whether a participant can omit certain choices from ranking or not. |
ranking.settings.not_applicable_label |
string | Text label that is shown to participant for "not applicable" option. |
rating_scale
question
Example
rating_scale
question
{
"element_id": 666974,
"type": "question",
"question": {
"question_text": "How likely is it that you would recommend us to a friend or colleague?",
"description_text": "",
"type": "rating_scale",
"rating_scale": {
"style": "net_promoter_score",
"left": {
"label": "Not at all likely",
"value": 0
},
"right": {
"label": "Extremely likely",
"value": 10
},
"step_size": 1
},
"settings": {
"is_required": false
}
}
}
Property | Type | Description |
---|---|---|
rating_scale.style |
string | Style of rating question. May be star_icons , tick_icons , heart_icons , user_icons , thumb_icons , slider or numerical_scale . |
rating_scale.left.label |
string | Text on the left side of the rating scale. |
rating_scale.left.value |
integer | Numeric value of left pole. |
rating_scale.right.label |
string | Text on the right side of the rating scale. |
rating_scale.right.value |
integer | Numeric value of right pole. |
rating_scale.step_size |
integer | Step size available to participant to select on the rating scale (e.g. rating from 1 to 5, with step size 1, allows to choose 1, 2, 3, 4 or 5). |
Collector API
Get all collectors from survey
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/collectors" \
-u "username:password"
Example response
{
"collectors": [
{
"collector_id": 479800,
"name": "Web Iframe 1",
"created_on": "2020-06-12T15:56:32+00:00",
"status": "closed"
},
{
"collector_id": 479799,
"name": "Email Invite 1",
"created_on": "2020-06-12T15:56:09+00:00",
"status": "active"
},
{
"collector_id": 99583,
"name": "Survey Link 1",
"created_on": "2018-02-27T19:13:54+00:00",
"status": "active"
}
]
}
Each survey can have multiple "collectors". Collectors are different options to collect responses, such as survey links, embed code, email invitations, etc. You can learn more about available collectors here: Different ways to collect responses
Each collector has a unique ID, and responses you collect will reference that ID. That way, you will know which collector (e.g. survey link) was used to collect a particular response, and you will also know which survey this collector belongs to (survey > collector > response).
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/collectors
Response properties
Property collectors
will contain an array with all collectors linked to the survey.
Property | Type | Description |
---|---|---|
collector_id |
integer | Unique identifier of the collector. |
name |
string | Name of the collector. This value was defined by the user who created it. |
created_on |
timestamp | Timestamp of when the collector was created. |
status |
string | Status of the collector. This can either be active (the collector can still collect new responses) or closed (the collector does not accept new responses). |
Get collector details
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/collectors/99583" \
-u "username:password"
Example response
{
"collector_id": 99583,
"name": "Survey Link 1",
"created_on": "2018-02-27T19:13:54+00:00",
"status": "active",
"number_of_responses": 87
}
This endpoint will return the details of a collector including the current number of responses collected by the specific collector.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/collectors/{collector_id}
Response properties
The object will contain the same properties as in the collector overview, with following addition:
Property | Type | Description |
---|---|---|
number_of_responses |
integer | Total number of responses collected with that very collector. |
Change collector status
Example request
curl -X POST "https://api.surveyhero.com/v1/surveys/53635/collectors/99583" \
-u "username:password" \
-F "status:closed"
Example response
{
"collector_id": 99583,
"name": "Survey Link 1",
"created_on": "2018-02-27T19:13:54+00:00",
"status": "closed",
"number_of_responses": 87
}
This endpoint allows you to either activate or close an existing collector. When a collector (e.g. survey link)
is active
it can be used for people to participate in your survey. When a collector is closed
, it is not possible to
participate in your survey with that collector anymore.
HTTP request
POST https://api.surveyhero.com/v1/surveys/{survey_id}/collectors/{collector_id}
Request parameters
Parameter | Type | Description |
---|---|---|
status |
string, required | Whether you want the collector to be active or closed . |
Response properties
The request will return the updated collector details.
Language API
Get all languages from survey
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/languages" \
-u "username:password"
Example response
{
"languages": [
{
"name": "English",
"code": "en",
"is_default": true,
"is_active": true
},
{
"name": "German",
"code": "de",
"is_default": false,
"is_active": false
}
]
}
Every survey has one main language (default), and may have additional languages (multilingual survey). You can list all available languages of your surveys here.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/languages
Response properties
Property languages
will contain an array with all languages of the survey.
Property | Type | Description |
---|---|---|
name |
string | English name of language (e.g. "German"). |
code |
string | Language code of survey (e.g. "de") |
is_default |
boolean | The default language is the main language of the survey (the language the survey was built in). Only one language can be default, and it will always be active. |
is_active |
boolean | Whether the language is active for participants to use. The default language will always be active. |
Response API
Get all responses
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/responses" \
-u "username:password"
Example response
{
"responses": [
{
"response_id": 3863473,
"collector_id": 99910,
"survey_id": 53635,
"started_on": "2018-02-27T20:14:29+00:00",
"last_updated_on": "2018-02-27T20:16:06+00:00",
"email_address": null,
"recipient_data": null,
"link_parameters": {
"client-id": 12345,
"company": "Acme Inc."
},
"language": {
"code": "de",
"name": "German"
},
"ip_address": null,
"meta_data": {
"device": "desktop",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"
},
"status": "completed"
},
{
"response_id": 3863469,
"collector_id": 99910,
"started_on": "2018-02-27T20:13:59+00:00",
"last_updated_on": "2018-02-27T20:14:27+00:00",
"email_address": null,
"recipient_data": null,
"link_parameters": null,
"language": {
"code": "en",
"name": "English"
},
"ip_address": null,
"meta_data": {
"device": "mobile",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532MT Build/MMB29T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.110 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/292.0.0.61.123;]"
},
"status": "incomplete"
}
]
}
With this endpoint you will get an overview of all responses given to your survey. Whenever someone participates in a
survey, this generates a response. If you need to get the actual answers given within
a response, you can simply access its response_id
.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses
Response properties
Property responses
will contain an array with all responses given to your survey, in ascending order (newest first).
Property | Type | Description |
---|---|---|
response_id |
integer | Unique identifier for the response. |
collector_id |
integer | Unique identifier of the collector that was used to collect the response. |
survey_id |
integer | Unique identifier of the survey. |
started_on |
timestamp | Timestamp of when the participant has opened your survey for the first time. |
last_updated_on |
timestamp | Timestamp of the last time the user navigated through your survey or submitted their answers (clicked "Back", "Next" or "Finish"). If the status of this response is completed , then last_updated_on represents the time of completion. |
access_code |
string|null | If the respondent was invited using our "Access Code" collector, their access code will show here. However, if you have set your survey to be "anonymous", this value will always be null . |
email_address |
string|null | If the respondent was invited using our "Email Invite" collector, their email address will show here. However, if you have set your survey to be "anonymous", this value will always be null . |
recipient_data |
object|null | Any additional information that was added to the Email Invite collector will show here. However, if there is none or if you have set your survey to be "anonymous", this value will always be null . |
link_parameters |
object|null | Any GET parameters that were added to the survey link of the participant will show here. However, if there are none or if you have set your survey to be "anonymous", this value will always be null . |
language |
object|null | In case of a multilingual survey, it will show the language that was chosen by participant. Will show null if not a multilingual survey. |
language.code |
string | Language code corresponding to selected language, e.g. "en" for English, "de" for German, etc. |
language.name |
string | Will show the language name in English, e.g. "English", "Spanish", etc. |
ip_address |
string|null | If the collector was set to save IP addresses, they will show here. However, if you have set your survey to be "anonymous", this value will always be null . |
meta_data |
object | Browser meta data such as device and user-agent information are being saved with each participation. The device can be either desktop , tablet or mobile and is derived from the browser's user agent information. |
status |
string | Participation status can either be incomplete or completed . Incomplete means that the participant has started, but not yet finished the survey. If last_updated_on is a long time ago, it might be a drop-off. |
Filtering responses
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/responses?status=completed" \
-u "username:password"
Example response
{
"responses": [
{
"response_id": 3863473,
"collector_id": 99910,
"started_on": "2018-02-27T20:14:29+00:00",
"last_updated_on": "2018-02-27T20:16:06+00:00",
"email_address": null,
"recipient_data": null,
"link_parameters": {
"client-id": 12345,
"company": "Acme Inc."
},
"language": {
"code": "de",
"name": "German"
},
"ip_address": null,
"meta_data": {
"device": "desktop",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36"
},
"status": "completed"
}
]
}
The ability to filter your responses is useful when you only need a subset of results. You can add any combination of GET parameters listed below to the HTTP request endpoint, and your responses will be filtered accordingly.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses?filter_key=filter_value&filter_key=filter_value
Available filters
The following key/value pairs can be used to filter your responses. They should be added as GET parameter to the URL. You can filter by multiple parameters.
Key | Value | Description |
---|---|---|
status |
string | You can filter by either completed or incomplete responses. |
started_on[from] |
timestamp | Get responses that have been started either at or after the provided time. Format of timestamp must be ISO 8601 (e.g. 2020-06-17T12:42:39+00:00 ). |
started_on[to] |
timestamp | Get responses that have been started either at or before the provided time. Format of timestamp must be ISO 8601 (e.g. 2020-06-17T12:42:39+00:00 ). |
last_updated_on[from] |
timestamp | Get responses which had their last update either at or after the provided time. Format of timestamp must be ISO 8601 (e.g. 2020-06-17T12:42:39+00:00 ). |
last_updated_on[to] |
timestamp | Get responses which had their last update either at or before the provided time. Format of timestamp must be ISO 8601 (e.g. 2020-06-17T12:42:39+00:00 ). |
collector_id |
integer|integer[] | Get responses that were collected with a specific collector, e.g. collector_id=99910 . You can also filter for multiple collectors, e.g. collector_id[]=99910&collector_id[]=99911 . |
Usage example
One common use case is to filter for completed responses within a specific period (e.g. yesterday). This could be achieved with following request:
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses?status=completed&last_updated_on[from]=2020-06-17T00:00:00+00:00&last_updated_on[to]=2020-06-17T23:59:59+00:00
The request above will only return survey responses that have been completed
between 2020-06-17T00:00:00+00:00
and 2020-06-17T23:59:59+00:00
.
Export responses as CSV/Excel file
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/responses?format=csv" \
-u "username:password"
Example response
Content-Disposition: attachment;filename="SurveyHero-Responses-2022-01-11.csv"
Content-Length: 5621
Content-Type: text/csv;charset=UTF-8
Body...
When using the browser version of SurveyHero, users can download pre-formatted CSV and Excel files of their responses. This is also possible via the API by adding format
as attribute to your GET request.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses?format={type}
Available formats
Allowed formats are csv
and excel
. Simply replace type
with one of the two, e.g. format=excel
. The format
attribute can be combined with any response filtering you may have applied, for example:
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses?status=completed&format=excel
The response body will contain all data and the response header will include Content-Type
, Content-Disposition
(recommended filename and extension) as well as Content-Length
. This information will allow you to process and save the response as a file.
Get all answers from response
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/responses/3863469" \
-u "username:password"
Example response
{
"response_id": 3875825,
"collector_id": 99910,
"started_on": "2018-02-28T16:32:24+00:00",
"last_updated_on": "2018-12-09T16:06:18+00:00",
"email_address": null,
"recipient_data": null,
"link_parameters": null,
"language": null,
"ip_address": null,
"meta_data": {
"device": "tablet",
"user-agent": "Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Mobile/15E148 Safari/604.1"
},
"status": "incomplete",
"previous_response_id": null,
"next_response_id": 8653465,
"answers": [
{
"element_id": 666812,
"question_text": "Do you have any further comments?",
"type": "text",
"text": "Everything was nicely organized, thank you!"
},
{
"element_id": 666974,
"question_text": "How likely is it that you would recommend us to a friend or colleague?",
"type": "number",
"number": 9
},
{
"element_id": 666809,
"question_text": "In which department do you work?",
"type": "choices",
"choices": [
{
"choice_id": 1745223,
"label": "Department B"
}
]
}
]
}
This endpoint allows you to retrieve all answers given within a response.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses/{response_id}
Response properties
The object will contain the same properties as in the responses overview, with following addition:
Property | Type | Description |
---|---|---|
previous_response_id |
integer|null | Unique identifier of the previous response. If null , then there is no previous response meaning this is the first available response. |
next_response_id |
integer|null | Unique identifier of the next response. If null , then there is no next response meaning this is the last available response. |
answers |
object[] | Array with one answer object per question in your survey. |
answers[].element_id |
integer | Unique identifier of the corresponding question within your survey. You can find all details about the question by looking up the question details. |
answers[].question_text |
string | Question text. |
answers[].type |
string | The type of the answer. Each answer type may have different properties. |
Get resume link
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/responses/3863469/resume" \
-u "username:password"
Example response
{
"url": "https://www.surveyhero.com/r/c2x9db2c/ynjxmhaykpdibcrz"
}
This endpoint will return the "resume link" for the specific response, allowing participation to be resumed where it was left off. This is useful for incomplete
responses.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/responses/{response_id}/resume
Response properties
Property | Type | Description |
---|---|---|
url |
string | Question text. |
Delete a response
Example request
curl -X DELETE "https://api.surveyhero.com/v1/surveys/53635/responses/3863469" \
-u "username:password"
Example response
{
"response_id": 3875825,
"status": "deleted"
}
This endpoint allows you to permanently delete collected responses.
HTTP request
DELETE https://api.surveyhero.com/v1/surveys/{survey_id}/responses/{response_id}
Response properties
The request will either return the response ID that was deleted, or an error message if deletion failed (e.g. because response was already deleted before).
Answer Types
Every answer object always consists of element_id
, question_text
, type
and an additional property named after
the type
. For example, if an answer is of type text
, then there will also be a property named text
.
Currently, following answer types exist: choice_table
, choices
, date
, file
, input_table
, inputs
, number
, ranking
and text
choice_table
answer
Example
choice_table
answer
{
"element_id": 666978,
"question_text": "On which days do you use following products:",
"type": "choice_table",
"choice_table": [
{
"row_id": 1745892,
"label": "Product A",
"choices": [
{
"choice_id": 177295,
"label": "Tue"
},
{
"choice_id": 177297,
"label": "Thu"
}
]
},
{
"row_id": 1745894,
"label": "Product C",
"choices": [
{
"choice_id": 177296,
"label": "Wed"
}
]
}
]
}
Property | Type | Description |
---|---|---|
choice_table |
object[] | Array of row objects. |
choice_table[].row_id |
integer | Unique identifier of row where selection was made. |
choice_table[].label |
string | Row description that was visible to participant. |
choice_table[].choices |
object[] | Array of choices that participant did select in this very row as their answer. |
choices
answer
Example
choices
answer
{
"element_id": 666967,
"question_text": "Which of these courses have you already attended?",
"type": "choices",
"choices": [
{
"choice_id": 1745870,
"label": "Course A"
},
{
"choice_id": 1745872,
"label": "Course C"
},
{
"choice_id": 0,
"label": "I think it was Course E"
}
]
}
Property | Type | Description |
---|---|---|
choices |
object[] | Array of choices that participant did select as their answer. |
date
answer
Example
date
answer
{
"element_id": 666971,
"question_text": "Please choose a date:",
"type": "date",
"date": "2018-02-15"
}
Property | Type | Description |
---|---|---|
date |
string|null | The date that was picked by the participant in format YYYY-MM-DD (e.g. "2018-02-15" ) or null if no selection was made. |
file
answer
Example
file
answer
{
"element_id": 1387752,
"question_text": "Please upload your image here:",
"type": "file",
"file": {
"name": "Galapagos.jpg",
"size": 480447,
"path": "/v1/download/element/1387752/response/3875825"
}
}
Property | Type | Description |
---|---|---|
file |
object|null | If a file was uploaded, its name, size and path will be available here. If no file was uploaded, this will be null . |
file.name |
string | The file name of the uploaded file. |
file.size |
integer | The file size of the uploaded file, in bytes. |
file.path |
string | The file path to download the file body. Follow this path to download the content of the uploaded file. |
input_table
answer
Example
input_table
answer
{
"element_id": 666981,
"question_text": "How many hours per day do you use following products:",
"type": "input_table",
"input_table": [
{
"row_id": 1745901,
"label": "Product A",
"columns": [
{
"column_id": 177302,
"label": "Tue",
"answer": {
"type": "number",
"number": 1.5
}
},
{
"column_id": 177304,
"label": "Thu",
"answer": {
"type": "number",
"number": 1.5
}
}
]
},
{
"row_id": 1745903,
"label": "Product C",
"columns": [
{
"column_id": 177303,
"label": "Wed",
"answer": {
"type": "number",
"number": 3
}
}
]
}
]
}
Property | Type | Description |
---|---|---|
input_table |
object[] | Array of row objects. |
input_table[].row_id |
integer | Unique identifier of row where input was made. |
input_table[].label |
string | Row description that was visible to participant. |
input_table[].columns |
object[] | Array of column objects. |
input_table[].columns[].column_id |
integer | Unique identifier of column where input was made. The combination of row_id and column_id gives you the "coordinate" within the table. |
input_table[].columns[].label |
string | Column description that was visible to participant. |
input_table[].columns[].answer |
object | Answer object with details about answer. |
inputs
answer
Example
inputs
answer
{
"element_id": 667012,
"question_text": "Please enter your contact details:",
"type": "inputs",
"inputs": [
{
"input_id": 1745983,
"label": "First and last name",
"answer": {
"type": "text",
"text": "John Smith"
}
},
{
"input_id": 1745985,
"label": "Postal code and city",
"answer": {
"type": "text",
"text": "8008 Zürich"
}
},
{
"input_id": 1745987,
"label": "Email address",
"answer": {
"type": "text",
"text": "support@surveyhero.com"
}
}
]
}
Property | Type | Description |
---|---|---|
inputs |
object[] | Array of input objects. |
inputs[].input_id |
integer | Unique identifier of input. |
inputs[].label |
string | Input description that was visible to participant. |
inputs[].answer |
object | Answer object with details about answer. |
number
answer
Example
number
answer
{
"element_id": 666974,
"question_text": "How likely is it that you would recommend us to a friend or colleague?",
"type": "number",
"number": 9
}
Property | Type | Description |
---|---|---|
number |
integer|null | Number that was entered or selected by the participant, or null if no answer was given. |
ranking
answer
Example
ranking
answer
{
"element_id": 1238491,
"question_text": "Please rank the following in order of importance to you, first being the most important:",
"type": "ranking",
"ranking": {
"ranked_choices": [
{
"choice_id": 3132165,
"label": "Health"
},
{
"choice_id": 3132166,
"label": "Family & Friends"
},
{
"choice_id": 3132167,
"label": "Purpose"
}
],
"not_applicable_choices": [
{
"choice_id": 3132169,
"label": "Money"
}
]
}
}
Property | Type | Description |
---|---|---|
ranking.ranked_choices |
object[] | Array containing the items that the participant considered in their ranking. The order of this array matches the ranking order done by the participant. |
ranking.not_applicable_choices |
object[] | Array containing the items that the participant did explicitly not consider in their ranking (marked as "not applicable"). |
text
answer
Example
text
answer
{
"element_id": 666811,
"question_text": "What is your full name?",
"type": "text",
"text": "John Smith"
}
Property | Type | Description |
---|---|---|
text |
string|null | Text that was entered by the participant, or null if not answer was given. |
Report API
Get tabulated results from survey
Example request
curl "https://api.surveyhero.com/v1/surveys/53635/report" \
-u "username:password"
Example response
{
"results": [
{
"element_id": 666759,
"question_text": "In which department do you work?",
"number_of_responses": 3,
"type": "choices",
"choices": [
{
"choice_id": 1745079,
"label": "Department A",
"count": 0,
"percentage": 0
},
{
"choice_id": 1745080,
"label": "Department B",
"count": 3,
"percentage": 100
},
{
"choice_id": 1745081,
"label": "Department C",
"count": 0,
"percentage": 0
}
]
},
{
"element_id": 666972,
"question_text": "How would you rate our product?",
"number_of_responses": 3,
"type": "rating_scale",
"rating_scale": {
"left": {
"label": "Miserable",
"value": 1
},
"right": {
"label": "Excellent",
"value": 5
},
"step_size": 1,
"values": [
{
"value": 4,
"count": 2,
"percentage": 66.67
},
{
"value": 5,
"count": 1,
"percentage": 33.33
}
],
"stats": {
"average": 4.33,
"standard_deviation": 0.47
}
}
},
{
"element_id": 666812,
"question_text": "Do you have any further comments?",
"number_of_responses": 3,
"type": "answers",
"answers": [
{
"response_id": 9497617,
"type": "text",
"text": "Very happy with the support I have received from James."
},
{
"response_id": 8653465,
"type": "text",
"text": "No, I have not."
},
{
"response_id": 3875825,
"type": "text",
"text": "Everything was nicely organized, thank you!"
}
]
}
]
}
This endpoint will return the complete and tabulated results from your survey ("Report").
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/report
Response properties
Property results
will contain an array with each question from your survey, including their tabulated results. The questions will be listed in the same order they are in your questionnaire.
Each array element will have following properties. However, the results
property will be different from question type to question type.
Property | Type | Description |
---|---|---|
element_id |
integer | Unique identifier for the element. |
question_text |
string | Question text. |
number_of_responses |
integer | Number of responses that this question has received. |
type |
string | Type of the result. Each result type has different properties. |
Result Types
Every result object always consists of element_id
, question_text
, number_of_responses
, type
and an additional property named after the type
. For example, if a result is of type choices
, then there will also be a property named choices
.
Currently, following result types exist: answers
, choice_table
, choices
, dates
, likert_scale
, likert_scale_table
, numeric_input_table
, numeric_inputs
, ranking
and rating_scale
answers
result
Example
answers
result
{
"element_id": 666811,
"question_text": "What is your full name?",
"number_of_responses": 2,
"type": "answers",
"answers": [
{
"response_id": 9497617,
"type": "text",
"text": "Shirley J. Lummus"
},
{
"response_id": 3875825,
"type": "text",
"text": "John Smith"
}
]
}
The Report API is about returning tabulated and aggregated data. However, certain question types, such as open text question, do not allow to aggregate data. In such cases, we simply return all answers
one by one.
Property | Type | Description |
---|---|---|
answers |
object[] | Array of answer objects, matching answer types of Response API. |
answers[].response_id |
integer | Unique identifier for the response. |
answers[].type |
string | The type of the answer, according to the different answer types declared in the Response API. |
choice_table
result
Example
choice_table
result
{
"element_id": 666978,
"question_text": "On which days do you use following products:",
"number_of_responses": 3,
"type": "choice_table",
"choice_table": [
{
"row_id": 1745892,
"label": "Product A",
"choices": [
{
"choice_id": 177294,
"label": "Mon",
"count": 0,
"percentage": 0
},
{
"choice_id": 177295,
"label": "Tue",
"count": 3,
"percentage": 42.86
},
{
"choice_id": 177296,
"label": "Wed",
"count": 1,
"percentage": 14.29
},
{
"choice_id": 177297,
"label": "Thu",
"count": 2,
"percentage": 28.57
},
{
"choice_id": 177298,
"label": "Fri",
"count": 1,
"percentage": 14.29
}
]
},
{
"row_id": 1745893,
"label": "Product B",
"choices": [
{
"choice_id": 177294,
"label": "Mon",
"count": 0,
"percentage": 0
},
{
"choice_id": 177295,
"label": "Tue",
"count": 0,
"percentage": 0
},
{
"choice_id": 177296,
"label": "Wed",
"count": 2,
"percentage": 100
},
{
"choice_id": 177297,
"label": "Thu",
"count": 0,
"percentage": 0
},
{
"choice_id": 177298,
"label": "Fri",
"count": 0,
"percentage": 0
}
]
}
]
}
Property | Type | Description |
---|---|---|
choice_table |
object[] | Array of row objects. |
choice_table[].row_id |
integer | Unique row identifier. |
choice_table[].label |
string | Row description. |
choice_table[].choices |
object[] | Array of choices that collected answers in this very row. |
choice_table[].choices[].choice_id |
integer | Unique choice identifier. |
choice_table[].choices[].label |
string | Choice description. |
choice_table[].choices[].count |
integer | How many times this choice was selected. |
choice_table[].choices[].percentage |
integer|float | How many times this choice was selected in relation the total amount of choices within that row. |
choices
result
Example
choices
result
{
"element_id": 666967,
"question_text": "Which of these courses have you already attended?",
"number_of_responses": 3,
"type": "choices",
"choices": [
{
"choice_id": 1745870,
"label": "Course A",
"count": 3,
"percentage": 100
},
{
"choice_id": 1745871,
"label": "Course B",
"count": 0,
"percentage": 0
},
{
"choice_id": 1745872,
"label": "Course C",
"count": 3,
"percentage": 100
},
{
"choice_id": 1745873,
"label": "Course D",
"count": 1,
"percentage": 33.33
},
{
"choice_id": 0,
"label": "Other",
"count": 2,
"percentage": 66.67,
"answers": [
{
"response_id": 8653465,
"type": "text",
"text": "Course E"
},
{
"response_id": 3875825,
"type": "text",
"text": "I think it was Course E"
}
]
}
]
}
Property | Type | Description |
---|---|---|
choices[] |
object[] | Array of choices that collected answers. |
choices[].choice_id |
integer | Unique choice identifier. |
choices[].label |
string | Choice description. |
choices[].count |
integer | How many times this choice was selected. |
choices[].percentage |
integer|float | How many times this choice was selected in relation to the number_of_responses for this question. |
choices[].answers |
object[] | If choice_id equals 0 , then the choice is an "Other" choice that did allow participants to enter their own choice text. These text entries will be listed here. |
dates
result
Example
dates
result
{
"element_id": 666971,
"question_text": "Please choose a date:",
"number_of_responses": 3,
"type": "dates",
"dates": [
{
"date": "2018-02-01",
"count": 2,
"percentage": 66.67
},
{
"date": "2018-02-15",
"count": 1,
"percentage": 33.33
}
]
}
Property | Type | Description |
---|---|---|
dates |
object[] | Array containing all selected dates. |
dates.date |
string | The date that was picked by the participant in format YYYY-MM-DD (e.g. "2018-02-15" ). |
dates.count |
integer | Number of times this date was selected. |
dates.percentage |
integer|float | How many times this date was selected in relation to the number_of_responses for this question. |
likert_scale
result
Example
likert_scale
result
{
"element_id": 666809,
"question_text": "How are you today?",
"number_of_responses": 3,
"type": "likert_scale",
"likert_scale": {
"values": [
{
"choice_id": 1745222,
"label": "Could be better",
"value": 1,
"count": 1,
"percentage": 33.33
},
{
"choice_id": 1745223,
"label": "OK",
"value": 2,
"count": 2,
"percentage": 66.67
},
{
"choice_id": 1745224,
"label": "Great!",
"value": 3,
"count": 0,
"percentage": 0
}
],
"stats": {
"average": 1.67,
"standard_deviation": 0.47
}
}
}
Property | Type | Description |
---|---|---|
likert_scale.values |
object[] | Array of value objects. |
likert_scale.values[].choice_id |
integer | Unique identifier of choice. |
likert_scale.values[].label |
string | Choice text. |
likert_scale.values[].value |
integer|null | The value that was selected on the likert scale. Is null if the choice was flagged as "not applicable". |
likert_scale.values[].count |
integer | The number of times this value was selected. |
likert_scale.values[].percentage |
integer|float|null | The number of times this value was selected in relation to the total number of responses. Is null if the choice was flagged as "not applicable". |
likert_scale.stats[].average |
integer|float | The overall average value across all responses. |
likert_scale.stats[].standard_deviation |
integer|float | The standard deviation across all answers. The lower the standard deviation, the more the participants agreed with their answers. The higher the standard deviation, the more the participants disagreed with their answers. |
likert_scale_table
result
Example
likert_scale_table
result
{
"element_id": 666976,
"question_text": "How often do you use following features:",
"number_of_responses": 3,
"type": "likert_scale_table",
"likert_scale_table": [
{
"row_id": 1745886,
"label": "Feature A",
"likert_scale": {
"values": [
{
"choice_id": 177290,
"label": "daily",
"value": 1,
"count": 0,
"percentage": 0
},
{
"choice_id": 177291,
"label": "weekly",
"value": 2,
"count": 2,
"percentage": 66.67
},
{
"choice_id": 177292,
"label": "monthly",
"value": 3,
"count": 1,
"percentage": 33.33
},
{
"choice_id": 177293,
"label": "yearly",
"value": 4,
"count": 0,
"percentage": 0
}
],
"stats": {
"average": 2.33,
"standard_deviation": 0.47
}
}
},
{
"row_id": 1745887,
"label": "Feature B",
"likert_scale": {
"values": [
{
"choice_id": 177290,
"label": "daily",
"value": 1,
"count": 0,
"percentage": 0
},
{
"choice_id": 177291,
"label": "weekly",
"value": 2,
"count": 1,
"percentage": 100
},
{
"choice_id": 177292,
"label": "monthly",
"value": 3,
"count": 0,
"percentage": 0
},
{
"choice_id": 177293,
"label": "yearly",
"value": 4,
"count": 0,
"percentage": 0
}
],
"stats": {
"average": 2,
"standard_deviation": 0
}
}
}
]
}
Property | Type | Description |
---|---|---|
likert_scale_table |
object[] | Array of row objects. |
likert_scale_table.row_id |
integer | Unique row identifier. |
likert_scale_table.label |
string | Row description. |
likert_scale_table.likert_scale.values |
object[] | Array of value objects. |
likert_scale_table.likert_scale.values[].choice_id |
integer | Unique identifier of choice. |
likert_scale_table.likert_scale.values[].label |
string | Choice text. |
likert_scale_table.likert_scale.values[].value |
integer|null | The value that was selected on the likert scale in this row. Is null if the choice was flagged as "not applicable". |
likert_scale_table.likert_scale.values[].count |
integer | The number of times this value was selected in this row. |
likert_scale_table.likert_scale.values[].percentage |
integer|float|null | The number of times this value was selected in relation to the total selections within that row. Is null if the choice was flagged as "not applicable". |
likert_scale_table.likert_scale.stats[].average |
integer|float | The overall average value across all responses in this row. |
likert_scale_table.likert_scale.stats[].standard_deviation |
integer|float | The standard deviation across all answers in this row. The lower the standard deviation, the more the participants agreed with their answers. The higher the standard deviation, the more the participants disagreed with their answers. |
numeric_input_table
result
Example
numeric_input_table
result
{
"element_id": 666981,
"question_text": "How many hours per day do you use following products:",
"number_of_responses": 3,
"type": "numeric_input_table",
"numeric_input_table": [
{
"row_id": 1745901,
"label": "Product A",
"columns": [
{
"column_id": 177301,
"label": "Mon",
"stats": {
"sum": 1,
"average": 1
}
},
{
"column_id": 177302,
"label": "Tue",
"stats": {
"sum": 2.5,
"average": 1.25
}
},
{
"column_id": 177303,
"label": "Wed",
"stats": {
"sum": 2,
"average": 2
}
},
{
"column_id": 177304,
"label": "Thu",
"stats": {
"sum": 1.5,
"average": 1.5
}
},
{
"column_id": 177305,
"label": "Fri",
"stats": {
"sum": null,
"average": null
}
}
]
},
{
"row_id": 1745902,
"label": "Product B",
"columns": [
{
"column_id": 177301,
"label": "Mon",
"stats": {
"sum": null,
"average": null
}
},
{
"column_id": 177302,
"label": "Tue",
"stats": {
"sum": 6,
"average": 6
}
},
{
"column_id": 177303,
"label": "Wed",
"stats": {
"sum": 2,
"average": 2
}
},
{
"column_id": 177304,
"label": "Thu",
"stats": {
"sum": null,
"average": null
}
},
{
"column_id": 177305,
"label": "Fri",
"stats": {
"sum": null,
"average": null
}
}
]
}
]
}
Property | Type | Description |
---|---|---|
numeric_input_table |
object[] | Array of row objects. |
numeric_input_table[].row_id |
integer | Unique row identifier. |
numeric_input_table[].label |
string | Row description. |
numeric_input_table[].columns |
object[] | Array of column objects. |
numeric_input_table[].columns[].column_id |
integer | Unique identifier of column. The combination of row_id and column_id gives you the "coordinate" within the table. |
numeric_input_table[].columns[].label |
string | Column description. |
numeric_input_table[].columns[].stats |
object | Tabulated answers entered into this table input. |
numeric_input_table[].columns[].stats.sum |
integer|float|null | Sum of values entered into numeric input. Is null if table input did not collect any responses. |
numeric_input_table[].columns[].stats.average |
integer|float|null | Average of values entered into numeric input. Is null if table input did not collect any responses. |
numeric_inputs
result
Example
numeric_inputs
result
{
"element_id": 1576276,
"question_text": "How many hours per day have you been working out:",
"number_of_responses": 2,
"type": "numeric_inputs",
"numeric_inputs": [
{
"input_id": 3925583,
"label": "Monday",
"stats": {
"sum": 2.5,
"average": 1.25
}
},
{
"input_id": 3925584,
"label": "Tuesday",
"stats": {
"sum": null,
"average": null
}
},
{
"input_id": 3925585,
"label": "Wednesday",
"stats": {
"sum": 2.5,
"average": 1.25
}
},
{
"input_id": 3925586,
"label": "Thursday",
"stats": {
"sum": null,
"average": null
}
},
{
"input_id": 3925587,
"label": "Friday",
"stats": {
"sum": null,
"average": null
}
},
{
"input_id": 3925588,
"label": "Saturday",
"stats": {
"sum": 1.5,
"average": 0.75
}
},
{
"input_id": 3925589,
"label": "Sunday",
"stats": {
"sum": 0.5,
"average": 0.5
}
}
]
}
Property | Type | Description |
---|---|---|
numeric_inputs |
object[] | Array of input objects. |
numeric_inputs[].input_id |
integer | Unique input identifier. |
numeric_inputs[].label |
string | Input description. |
numeric_inputs[].stats |
object | Tabulated answers entered into this table input. |
numeric_inputs[].stats.sum |
integer|float|null | Sum of values entered into numeric input. Is null if input did not collect any responses. |
numeric_inputs[].stats.average |
integer|float|null | Average of values entered into numeric input. Is null if input did not collect any responses. |
ranking
result
Example
ranking
result
{
"element_id": 1238491,
"question_text": "Please rank the following in order of importance to you, first being the most important:",
"number_of_responses": 3,
"type": "ranking",
"ranking": [
{
"choice_id": 3132165,
"label": "Health",
"score": 8,
"distribution": [
{
"position": 1,
"count": 2
},
{
"position": 3,
"count": 1
}
]
},
{
"choice_id": 3132166,
"label": "Family & Friends",
"score": 5,
"distribution": [
{
"position": 2,
"count": 2
}
]
},
{
"choice_id": 3132167,
"label": "Purpose",
"score": 5,
"distribution": [
{
"position": 1,
"count": 1
},
{
"position": 3,
"count": 1
},
{
"position": 4,
"count": 1
}
]
},
{
"choice_id": 3132168,
"label": "Freedom",
"score": 2,
"distribution": [
{
"position": 3,
"count": 1
}
]
},
{
"choice_id": 3132169,
"label": "Money",
"score": 0,
"distribution": []
}
]
}
Property | Type | Description |
---|---|---|
ranking |
object[] | Array containing all items available for ranking. The order of this array matches the overall ranking order (first to last). |
ranking[].choice_id |
integer | Unique choice identifier. |
ranking[].label |
string | Choice text. |
ranking[].score |
integer | Overall ranking score of this very item. The first ranked item will have the highest score. |
ranking[].distribution |
object[] | Array of rankings for this very choice. |
ranking[].distribution[].position |
integer | Position where this choice was ranked in. |
ranking[].distribution[].count |
integer | How many times the choice was ranked in this position. |
rating_scale
result
Example
rating_scale
result
{
"element_id": 666974,
"question_text": "How likely is it that you would recommend us to a friend or colleague?",
"number_of_responses": 3,
"type": "rating_scale",
"rating_scale": {
"left": {
"label": "Not at all likely",
"value": 0
},
"right": {
"label": "Extremely likely",
"value": 10
},
"step_size": 1,
"values": [
{
"value": 9,
"count": 2,
"percentage": 66.67
},
{
"value": 10,
"count": 1,
"percentage": 33.33
}
],
"stats": {
"average": 9.33,
"standard_deviation": 0.47,
"net_promoter_score": {
"detractors": {
"count": 0,
"percentage": 0
},
"passives": {
"count": 0,
"percentage": 0
},
"promoters": {
"count": 3,
"percentage": 100
},
"score": 100
}
}
}
}
Property | Type | Description |
---|---|---|
rating_scale.left.label |
string | Text on the left side of the rating scale. |
rating_scale.left.value |
integer | Numeric value of left pole. |
rating_scale.right.label |
string | Text on the right side of the rating scale. |
rating_scale.right.value |
integer | Numeric value of right pole. |
rating_scale.step_size |
integer | Step size available to participant to select on the rating scale (e.g. rating from 1 to 5, with step size 1, allows to choose 1, 2, 3, 4 or 5). |
rating_scale.values |
object[] | Array of value objects. |
rating_scale.values[].value |
integer | The value that was selected on the rating scale. |
rating_scale.values[].count |
integer | The number of times this value was selected. |
rating_scale.values[].percentage |
integer|float | The number of times this value was selected in relation to the number_of_responses . |
rating_scale.stats[].average |
integer|float | The overall average value across all responses. |
rating_scale.stats[].standard_deviation |
integer|float | The standard deviation across all answers. The lower the standard deviation, the more the participants agreed with their answers. The higher the standard deviation, the more the participants disagreed with their answers. |
rating_scale.stats[].net_promoter_score |
object | Net Promoter Score (NPS) is a very specific question type that requires a rating scale from 0 to 10 with step size 1. If the rating scale matches these requirements, the net_promoter_score will be included in the stats object. |
rating_scale.stats[].net_promoter_score.detractors |
object | Participants that selected a value between 0 and 6. |
rating_scale.stats[].net_promoter_score.detractors.count |
integer | Number of detractors. |
rating_scale.stats[].net_promoter_score.detractors.percentage |
integer|float | Number of detractors in relation to the number_of_responses . |
rating_scale.stats[].net_promoter_score.passives |
object | Participants that selected a value between 7 and 8. |
rating_scale.stats[].net_promoter_score.passives.count |
integer | Number of passives. |
rating_scale.stats[].net_promoter_score.passives.percentage |
integer|float | Number of passives in relation to the number_of_responses . |
rating_scale.stats[].net_promoter_score.promoters |
object | Participants that selected a value between 9 and 10. |
rating_scale.stats[].net_promoter_score.promoters.count |
integer | Number of promoters. |
rating_scale.stats[].net_promoter_score.promoters.percentage |
integer|float | Number of promoters in relation to the number_of_responses . |
rating_scale.stats[].net_promoter_score.score |
integer|float | Calculated net promoter score (promoters.percentage minus detractors.percentage ). |
Webhooks API
Introduction to webhooks
SurveyHero can send notifications to your application any time an event happens with one of your surveys. This is especially useful for events that are not triggered by a direct API request. For example, the most requested webhook is for "newly submitted survey responses".
You can register webhook URLs that we will notify any time an event happens. When the event occurs - for example, a new survey response was submitted - SurveyHero will make an HTTP POST request to any endpoints that you have provided us. Each request will contain all the relevant information about what just happened, including the type of event and the data associated with that event.
Receiving webhook notifications
Webhook data is sent as JSON (Content-Type: application/json
) in the POST request body.
To acknowledge receipt of a webhook, your endpoint must return a 2xx
HTTP status code, with a timeout of 10 seconds. All response codes outside this range will indicate to SurveyHero that you did not receive or where not able to successfully process the webhook
notification.
If your endpoint does not respond with a 2xx
HTTP status code within 10 seconds (timeout), SurveyHero will attempt to deliver your webhooks again later. We will attempt to deliver your webhooks for up to three days, with hourly pauses between every retry.
A great resource for testing is Webhook Tester. This service allows you to create temporary endpoints and to view incoming webhook notifications in real-time.
Example webhook payload
Example webhook notification payload
{
"message_id": "356042f5-44d7-416f-8c71-b5b254b9baa5",
"triggered_on": "2018-12-09T16:06:18+00:00",
"webhook": {
"webhook_id": 1,
"event_type": "response.completed",
"url": "https://webhook.site/a4ed275d-9954-4fe1-91ea-2ec4da5016e8",
"status": "active",
"created_on": "2018-12-09T16:02:25+00:00"
},
"data": {
// Data specific to event type, e.g. complete survey response
}
}
Each webhook notification will contain this information. The content of the data
property will change based on
the event type.
Property | Type | Description |
---|---|---|
message_id |
string | Unique message identifier. Every webhook notification will have a unique message ID. If a delivery fails and we retry again, the ID will remain the same. |
triggered_on |
timestamp | Timestamp of when the event was triggered. |
webhook |
object | The corresponding webhook that is responsible for this request. |
data |
object | The data corresponding to the event type. In case of event type response.completed for example, this will be the complete survey response. |
Webhooks Endpoints
Here is an overview of the available actions to manage your webhooks:
HTTP request | Description |
---|---|
GET https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks |
List all webhooks of survey. |
POST https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks |
Create a new webhook for survey. |
GET https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id} |
Get details of specific webhook. |
POST https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id} |
Update specific webhook. |
DELETE https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id} |
Delete specific webhook. |
List existing webhooks
Example request
curl "https://api.surveyhero.com/v1/surveys/1000/webhooks" \
-u "username:password"
Example response
{
"webhooks": [
{
"webhook_id": 1000,
"event_type": "response.completed",
"url": "https://webhook.site/a4ed275d-9954-4fe1-91ea-2ec4da5016e8",
"status": "active",
"created_on": "2018-12-09T16:02:25+00:00"
},
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "paused",
"created_on": "2018-12-09T16:41:37+00:00"
}
]
}
You can view all defined webhooks of a specific survey. You can then use the webhook_id
to make
an update to or delete a webhook.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks
Response properties
Property | Type | Description |
---|---|---|
webhook |
object[] | Array with one object per available webhook. |
Create a new webhook
Example request
curl -X POST "https://api.surveyhero.com/v1/surveys/1000/webhooks" \
-u "username:password" \
-F "event_type=response.completed" \
-F "url=https://integration.acme-company.com/process-new-response"
Example response
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "active",
"created_on": "2018-12-09T16:41:37+00:00"
}
You can simply create a new webhook for a survey by navigating to the specific survey's resource and making an HTTP POST request with the required parameters.
HTTP request
POST https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks
Request parameters
Parameter | Type | Description |
---|---|---|
event_type |
string, required | The type of event you want to be notified about (e.g. response.completed ). Every event type will return its own set of data. |
url |
string, required | The URL where you want us to send the notifications. This should be an active endpoint, pointing to your application or server. You may want to use Webhook Tester for testing. |
status |
string | Whether the webhook should be active (default) or paused . |
Response properties
The request will either return the newly created webhook details on success, or an error message if creation failed (
e.g. because of missing or invalid url
parameter).
Retrieve a single webhook
Example request
curl "https://api.surveyhero.com/v1/surveys/1000/webhooks/1001" \
-u "username:password"
Example response
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "active",
"created_on": "2018-12-09T16:41:37+00:00"
}
Retrieve the details of a specific webhook.
HTTP request
GET https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id}
Response properties
Property | Type | Description |
---|---|---|
webhook_id |
integer | Unique identifier for the webhook. |
event_type |
string | What event the webhook is notifying about. Here is an overview: All event types |
url |
string | The endpoint where we will send notifications to. |
status |
string | Whether the webhook is active (default) or paused . |
created_on |
timestamp | Timestamp of when the webhook was created. |
Update an existing webhook
Example request
curl -X POST "https://api.surveyhero.com/v1/surveys/1000/webhooks/1001" \
-u "username:password" \
-F "status=paused"
Example response
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "paused",
"created_on": "2018-12-09T16:41:37+00:00"
}
You can always update an existing webhook. You can either change the url
or change the webhook status
.
HTTP request
POST https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id}
Request parameters
Parameter | Type | Description |
---|---|---|
url |
string | The URL where you want us to send the notifications. This should be an active endpoint, pointing to your application or server. |
status |
string | Whether the webhook should be active (default) or paused . |
Response properties
The request will either return the updated webhook details on success, or an error message if the update failed (e.g.
because of invalid url
parameter).
Delete a webhook
Example request
curl -X DELETE "https://api.surveyhero.com/v1/surveys/1000/webhooks/1001" \
-u "username:password"
Example response
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "deleted",
"created_on": "2018-12-09T16:41:37+00:00"
}
You can simply delete webhooks when you do not need them anymore. Alternatively, you can
also change its status
to paused
.
HTTP request
DELETE https://api.surveyhero.com/v1/surveys/{survey_id}/webhooks/{webhook_id}
Response properties
The request will either return the webhook that was deleted, or an error message if deletion failed (e.g. because webhook was already deleted before).
Webhooks Event Types
Currently, following event types are available: email.feedback
, response.completed
, survey.created
and survey.deleted
Both survey.created
and survey.deleted
are only available as Global Webhooks.
Would you like to get notified about other survey related events? If yes, then please contact us and let us know your use case.
email.feedback
event type
Example
email.feedback
webhook payload
{
"message_id": "241c974f-1496-47a0-8968-78e608602f4a",
"triggered_on": "2021-12-31T14:07:02+00:00",
"webhook": {
"webhook_id": 1671,
"event_type": "email.feedback",
"url": "https://integration.acme-company.com/process-email-feedback",
"status": "active",
"created_on": "2021-12-31T14:05:17+00:00"
},
"data": {
"email_address": "does-not-exist@surveyhero.com",
"feedback_type": "hard_bounce"
}
}
This event type will notify you about any email related feedback that we receive when sending email invitations on your behalf (using our "Email Invite" collector).
When we send emails on your behalf, we keep track of any bounces, complaints or unsubscribes we receive. This webhook allows you to receive that information as well.
Property | Type | Description |
---|---|---|
email_address |
string | The email address that the notification is about. |
feedback_type |
string | The feedback type can be one of the following: soft_bounce , hard_bounce , complaint or unsubscribed |
response.completed
event type
Example
response.completed
webhook payload
{
"message_id": "43b076f4-1f8d-4b39-a866-1329dfcd5e06",
"triggered_on": "2021-12-31T14:09:46+00:00",
"webhook": {
"webhook_id": 1672,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "active",
"created_on": "2021-12-31T14:05:25+00:00"
},
"data": {
"response_id": 45638152,
"collector_id": 721593,
"survey_id": 716241,
"started_on": "2021-12-31T14:09:30+00:00",
"last_updated_on": "2021-12-31T14:09:46+00:00",
"email_address": "john.doe@example.com",
"recipient_data": {
"name": "John Doe",
"company": "Example Inc."
},
"link_parameters": null,
"language": null,
"ip_address": "104.134.212.22",
"meta_data": {
"device": "desktop",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62"
},
"status": "completed",
"previous_response_id": null,
"next_response_id": null,
"answers": [
{
"element_id": 4800046,
"question_text": "Were we able to answer your questions to your satisfaction?",
"type": "choices",
"choices": [
{
"choice_id": 11994336,
"label": "Yes"
}
]
},
{
"element_id": 4800047,
"question_text": "Do you have any further comments?",
"type": "text",
"text": "No, thank you."
}
]
}
}
With this event type, we will notify you about any completed survey responses you receive.
The data
of the webhook payload will contain a full response including answers.
Global Webhooks
Example request
curl -X POST "https://api.surveyhero.com/v1/webhooks" \
-u "username:password" \
-F "event_type=response.completed" \
-F "url=https://integration.acme-company.com/process-new-response"
Example response
{
"webhook_id": 1001,
"event_type": "response.completed",
"url": "https://integration.acme-company.com/process-new-response",
"status": "active",
"created_on": "2018-12-09T16:41:37+00:00"
}
Webhooks can also be set on an "account level", meaning that all your surveys will be triggering the same set of webhooks automatically. That way, you do not need to set up the same webhooks for each survey individually. Instead, with global webhooks, every existing survey as well as future surveys created by you will be triggering these webhooks.
To create webhooks on an account level simply use endpoint https://api.surveyhero.com/v1/webhooks
instead of a survey
specific endpoint. You can use the same actions as described here.
Additional event types
Example webhook notification payload
{
"message_id": "14a468b8-50bc-4ea6-a135-a747d60db9b3",
"triggered_on": "2022-05-23T13:21:34+00:00",
"webhook": {
"webhook_id": 1806,
"event_type": "survey.created",
"url": "https://integration.acme-company.com/process-new-survey",
"status": "active",
"created_on": "2022-05-23T13:21:05+00:00"
},
"data": {
"survey_id": 1341325
}
}
In addition to the event types listed above, there are other even types that are only available on a global level (not survey specific): survey.created
and survey.deleted
Errors
Example error response
{
"error": {
"code": 40140,
"message": "Authentication failed: API key is deactivated"
}
}
When consuming our API you may face errors. We try to make them as descriptive as possible, so you can resolve them as easily as possible. In general, codes in the 2xx
range indicate success, codes in the 4xx
range are errors caused in your request while codes in the 5xx
range are errors on our end. Here is an overview of different errors and their meaning.
HTTP Status | Error Code | Meaning |
---|---|---|
400 | 40000 | Bad Request |
400 | 40010 | Missing required parameter, unable to complete request |
400 | 40020 | Invalid parameter value, unable to complete request |
400 | 40030 | Duplicate value: Request could not be completed because value already exists |
401 | 40100 | Unauthorized |
401 | 40110 | Authentication failed: Missing or incomplete authorization header |
401 | 40120 | Authentication failed: Invalid format of credentials in authorization header |
401 | 40130 | Authentication failed: Unknown credentials in authorization header |
401 | 40140 | Authentication failed: API key is deactivated |
402 | 40200 | Upgrade required |
403 | 40300 | Forbidden |
403 | 40310 | Forbidden: You are not allowed access to this survey |
403 | 40320 | Forbidden: You are not allowed access to this webhook |
404 | 40400 | Resource Not Found |
404 | 40450 | Resource Not Found: Response ID does not belong to survey ID |
405 | 40500 | Method Not Allowed |
429 | 42910 | Too Many Requests: Please do not make more than 2 requests per second |
500 | 50000 | Internal Server Error |
503 | 50300 | Service Unavailable |
Feedback and Support
Thank you for your interest in our API.
We will be continuously adding new and exciting capabilities to it. Feedback is very welcome and if you need to be able to do something programmatically that is not possible yet, please let us know!