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.
Example of a paged request/response
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.
Response
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}"
    }
}
Example of a streamed request/response
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.
Response
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.
Example of simple request
GET  https://<host>/v1/surveys/p1231234/responses/data/1?variables=q1,q2 HTTP/1.1
Accept: application/json
Authorization: Bearer <access_token>
Response
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.
Basic example
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.
Response
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.
Example with custom key-validation
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.
Response
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.

Example with hierarchical 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".
Response
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.
Example with data-validation
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.
Response
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.
Basic example
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"
        }
    ]
}
Response
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.
Response
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.
Request
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.
Response
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.

Deleting with responseid-key.
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
        }
    ]
}
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
    "deletedRecords": 2
}
Deleting with custom-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" (2)
        }
    ]
}
1 This key exists in the database.
2 This key does not exist in the database.
Response
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.
Deleting from a loop-level.
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.
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
    "deletedRecords": 3
}

Using a non-unique key

Deleting with 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.
Response
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.