Interact with Response Data
Read Responses
Responses are returned as a collection or stream of SurveyDataRecords where each record contains datapoints as Key-Value pairs. Datapoints with a blank value in the database will not be serialized. This means that if you get variables email and gender, two records can contain different properties depending on whether or not the datapoints have values. For example: "{"respid": 1, "email":"test@example.com"}" "{"respid": 2, "email":"test2@example.com", "gender":"male"}"
The '/v1/surveys/{surveyId}/responses/data' - endpoint includes some QueryParameters alowing you to customize the response:
-
variables - a comma-separated list of variable names.
-
variableTemplateId - the id of a Variable Template created in Survey Designer.
-
filterExpression - an expression to filter the response records.
-
pageSize - an integer describing the number of records to return for a 'paged' - response.
-
page - an integer describing which page of size pageSize to return for a 'paged' - response.
variables and variableTemplateId are mutually exlcusive, meaning only one of them can be used in a request. If neither are provided, all datapoints from all schema levels will be returned. |
Response records can be returned in different formats. You use the Accept-header to control the type of response to retrieve. See the examples below for usage of the header. |
The maximum pageSize is set to 10000 records. PageSize larger than 10000 will result in a BadRequest (400) response. Our streaming response is not affected by this limit. |
GET https://<host>/v1/surveys/p1231234/responses/data?variables=q1,q3&pageSize=2&page=1 HTTP/1.1
Accept: application/json (1)
Authorization: Bearer <access_token>
1 | application/json is the default and will return the records as one collection of pageSize items. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"itemCount": 2,
"totalCount": 200,
"items": [
{"responseid": 1, "q1": "C1", "q3": "01456"},
{"responseid": 2, "q1": "C2", "q3": "333445"}
],
"links":
{
"next": "https://<host>/v1/surveys/p1231234/responses/data?variables=q1,q3&pageSize=2&page=2",
"item": "https://<host>/v1/surveys/p1231234/responses/data/{responseId}"
}
}
GET https://<host>/v1/surveys/p1231234/responses/data?variables=q1,q3 HTTP/1.1
Accept: application/x-ndjson (1)
Authorization: Bearer <access_token>
1 | application/x-ndjson will return the records as a stream of new-line delimitted SurveyDataRecords. |
HTTP/1.1 200 OK
Content-Type: application/x-ndjson; charset=utf-8
{"responseid": 1, "q1": "C1", "q3": "01456"}
{"responseid": 2, "q1": "C2", "q3": "333445"}
Read a single Response
If you have a unique ResponseId for a response, you can use the '/v1/surveys/{surveyId}/responses/data/{responseId}' - endpoint to get the SurveyDataRecord for that response.
-
variables - a comma-separated list of variable names.
-
variableTemplateId - the id of a Variable Template created in Survey Designer.
variables and variableTemplateId are mutually exlcusive, meaning only one of them can be used in a request. If neither are provided, all datapoints from all schema levels will be returned. |
GET https://<host>/v1/surveys/p1231234/responses/data/1?variables=q1,q2 HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"responseid": 1,
"q1": "C1",
"q2": "01456"
}
Add Responses
Responses are added by POST-ing records to the '/v1/surveys/{surveyId}/responses/data/{responseId}' - endpoint. The payload is an object that contains two properties; "dataSchema" and "data". The "dataSchema" is optional, and if this is not included the api will just pick out the datapoints from the data records and leave the rest blank.
The format of the records you add to the POST payload is the same as the format you get from the GET '/v1/surveys/{surveyId}/responses/data/{responseId}' - endpoint. |
POST https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"data": [ (1)
{
"gender": "male",
"city": "oslo"
},
{
"gender": "female",
"country": "norway"
}
]
}
1 | This will add two new response records. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"insertedRecords": 2,
"insertedIds": [23,24] (1)
}
1 | Two new records with ResponseIds 23 and 24. |
POST https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"],
"variables": ["gender", "city", "country"]
},
"data": [
{
"email": "test1@example.com", (1)
"gender": "male",
"city": "oslo"
},
{
"email": "test2@example.com",
"gender": "female",
"country": "norway"
}
]
}
1 | This email already exists in the database. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"insertedRecords": 1, (1)
"insertedIds": [214],
"validationMessages": { (2)
"level": "response",
"rowResults": [
{
"rowNumber": 1,
"messages": [
{
"fields": ["email"],
"message": "KeyValue already exists.",
"value": "test1@example.com", (3)
"severity": "Error"
}
]
}
]
}
}
1 | Only one out of the two records was inserted. |
2 | Note the "validationMessages" property. |
3 | This value already exists in the survey database. |
Adding hierarchical data
You add hierarchical data in the same way as you add top-level data, and the structure is the same as in the records with hierarchical data you get when reading data.
POST https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"data": [
{
"gender": "male",
"city": "oslo",
"cars": [ (1)
{
"cars": "bmw",
"tested": "yes"
},
{
"cars": "ford",
"tested": "no"
}
]
},
{
"email": "test2@example.com",
"gender": "female",
"country": "norway",
"cars": [
{
"cars": "bmw",
"tested": "yes"
},
{
"cars": "ford",
"tested": "no"
}
]
}
]
}
1 | "cars" is a loop with iteration codes "bmw" and "ford". |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"insertedRecords": 2,
"insertedIds": [23,24]
}
Adding invalid data
If you POST some records and one of the datapoints contains invalid data, the whole operation will abort and a validation message is returned.
A 400 response from the Api will leave the response data in the survey database untouched. |
POST https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"data": [
{
"gender": "male",
"city": "oslo",
"age": "abc" (1)
},
{
"gender": "female",
"country": "norway",
"date_of_birth": "abc" (2)
}
]
}
1 | This is not a number. |
2 | This is not a date. |
HTTP/1.1 400 BadRequest
Content-Type: application/json; charset=utf-8
{
"message": "Change survey data operation is aborted. No data was changed.",
"validationMessages": {
"level": "response",
"rowResults": [
{
"rowNumber": 1,
"messages": [
{
"fields": ["age"],
"message": "Invalid Numeric.",
"value": "abc",
"severity": "Error"
}
]
},
{
"rowNumber":2,
"messages": [
{
"fields": ["date_of_birth"],
"message": "Invalid DateTime.",
"value": "abc",
"severity": "Error"
}
]
}
]
}
}
Update Responses
Responses are updated by PUT-ing records to the '/v1/surveys/{surveyId}/responses/data' - endpoint. The payload is an object that contains two properties; "dataSchema" and "data". The "dataSchema" is required, and it must contain both the keys to match each record and the variable names to be updated.
Data validation is the same as for POST, and a 400 - BadRequest will be returned if any of the datapoints contain invalid values.
The format of the records you add to the PUT payload is the same as the format you get from the GET '/v1/surveys/{surveyId}/responses/data' - endpoint. |
Datapoints on a record with a variable name that is not specified in the "dataSchema" will be ignored by the Api. |
PUT https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"],
"variables": ["gender", "city", "country"]
},
"data": [
{
"email": "test1@example.com",
"gender": "male",
"city": "oslo"
},
{
"email": "test2@example.com",
"gender": "female",
"country": "norway"
}
]
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"updatedRecords": 2
}
Updating with invalid keys
Only the records with a matching key will be updated. Records with a key not found in the database will be listed in the "validationMessages".
PUT https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"],
"variables": ["gender", "city", "country"]
},
"data": [
{
"email": "test1@example.com", (1)
"gender": "male",
"city": "oslo"
},
{
"email": "test2@example.com", (2)
"gender": "female",
"country": "norway"
}
]
}
1 | This value exists in the database. |
2 | This value does not exist in the database. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"updatedRecords": 1,
"validationMessages": {
"level": "response",
"rowResults": [
{
"rowNumber": 2,
"messages": [
{
"fields": ["email"],
"message": "KeyValue could not be found.",
"value": "test2@example.com",
"severity": "Error"
}
]
}
]
}
}
Merge Responses
Responses are merged by PATCH-ing records to the '/v1/surveys/{surveyId}/responses/data' - endpoint. The payload is an object that contains two properties; "dataSchema" and "data". The "dataSchema" is required, and must contain both the keys to match each record and the variable names to update.
The PATCH operation will update all records that have a matching key, and will add any records with a key that does not matching existing data.
Validation of data is the same as for POST, and a 400 - BadRequest will be returned if any of the datapoints contain invalid values.
The format of the records you add to the PUT payload is the same as the format you get from the GET '/v1/surveys/{surveyId}/responses/data' - endpoint. |
Any datapoints on a record that has a variable name that is not specified in the "dataSchema" will be ignored by the Api. |
PATCH https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"],
"variables": ["gender", "city", "country"]
},
"data": [
{
"email": "test1@example.com", (1)
"gender": "male",
"city": "oslo"
},
{
"email": "test2@example.com", (2)
"gender": "female",
"country": "norway"
}
]
}
1 | This key already exists in the database and will be updated. |
2 | This key does not exist and will be added. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"insertedRecords": 1,
"insertedIds": [43334],
"updatedRecords": 1
}
Delete Responses
Responses are deleted by DELETE-ing records to the '/v1/surveys/{surveyId}/responses/data' - endpoint. The payload is an object that contains two properties; "dataSchema" and "data". The "dataSchema" is required, and must contain both the keys to match each record. No "variables" are required for this operation.
The DELETE operation will delete records that have matching keys. Records with a key that does not match a record in the database will be listed in the "validationMessages" of the HTTP Response.
Validation of data is the same as for POST, a 400 - BadRequest will be returned if any of the datapoints contain invalid key values.
Deleting from top-level
If you delete a record from the top level, all loop records with the given key will also be deleted from all sub-levels.
DELETE https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["responseid"]
},
"data": [
{
"responseid": 12
},
{
"responseid": 23
}
]
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"deletedRecords": 2
}
DELETE https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"]
},
"data": [
{
"email": "test1@example.com" (1)
},
{
"email": "test2@example.com" (2)
}
]
}
1 | This key exists in the database. |
2 | This key does not exist in the database. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"deletedRecords": 1,
"validationMessages": {
"level": "response",
"rowResults": [
{
"rowNumber": 2,
"messages": [
{
"fields": ["email"],
"message": "KeyValue could not be found.",
"value": "test2@example.com",
"severity": "Error"
}
]
}
]
}
}
Deleting from a loop level
When deleting records in a loop level you must provide the combined keys for that level. All loop records in all sub-levels with the matching set of keys will also be deleted. Only system variables are supported as keys. The schema also needs the "name" of the level you want to delete from. The default level is "response" so for top-level deletion it is not required.
The loop records are flat and not in a nested form as is the case with POST/PUT/PATCH. |
DELETE https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["responseid", "l1"], (1)
"name": "l1" (2)
},
"data": [
{
"responseid": 12,
"l1": "1"
},
{
"responseid": 12,
"l1": "2"
},
{
"responseid": 34,
"l1": "3"
}
]
}
1 | The "keys" property needs to include all the keys down to this level. |
2 | We want to delete records from "l1" and below. |
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"deletedRecords": 3
}
Using a non-unique key
DELETE https://<host>/v1/surveys/p1231234/responses/data HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
{
"dataSchema": {
"keys": ["email"]
},
"data": [
{
"email": "test1@example.com" (1)
},
{
"email": "test2@example.com"
}
]
}
1 | This key exists on several rows in the database. |
HTTP/1.1 400 BadRequest
Content-Type: application/json; charset=utf-8
{
"deletedRecords": 0,
"validationMessages": {
"level": "response",
"rowResults": [
{
"rowNumber": 1,
"messages": [
{
"fields": ["email"],
"message": "KeyValue is not unique.",
"value": "test1@example.com",
"severity": "Error"
}
]
}
]
}
}
Filter Responses
Use the filterExpression query parameter to filter the set of responses you want to get from the Api. See Create Filter Expressions for more information on syntax and usage.