Inserting Responses
Use the SmartSurvey API to add completed, partial, or disqualified responses to a survey.
Use the API to add responses to a survey — completed, partial, or disqualified — just as if someone had filled it in. This is useful for integrations that collect answers elsewhere, and for importing historical responses.
Endpoint
POST {base_url}/surveys/{surveyId}/responses| Authentication | Basic auth — Authorization: Basic base64(api_token:api_secret) |
| Permission | Your API key must have permission to add responses to the survey |
| Body | JSON (application/json), or multipart/form-data when the survey has file-upload questions |
| Query | ?return=full | minimal | none (default minimal) |
Request body
| Field | Type | Description |
|---|---|---|
status | string (required) | completed, partial, or disqualified |
questions | array | The answers, grouped by question (see below) |
variables | array | { "name", "value" } pairs to store against the response, matched to the survey's variables |
completion_actions | string | For completed responses, which follow-up actions to run: all (default), no_email (everything except notification emails), or none (record the response only — no emails, webhooks, integrations or AI). Use none when importing |
tracking_link_id | integer | Attribute the response to a specific collector/link; omit for the survey default |
translation_id | integer | The survey's language/translation id; omit to use the default |
unique_id | string | Your own unique reference for the response |
date_started / date_ended | date-time | When the response was started/finished; set these when importing past responses |
generate_save_and_continue_link | boolean | For a partial response, return a link to resume it later |
Supplying answers
Each item in questions is { "id": <questionId>, "answers": [ … ] }. The fields you set on each answer depend on the question type:
| Question type | How to answer |
|---|---|
| Radio, dropdown, list, single image, CSAT, CES, FFT, EES, ESAT, ENPS | one answer: choice_id |
| Checkbox / multi-select | one answer per selected option (choice_id each) |
| An “other” option | set choice_id for the option and value for the typed-in text |
| Single text box, essay, single date | one answer: value only |
| Multiple text boxes, multi-date range, AI Follow-Up | one answer per input: choice_id (the input) and value |
| Matrix (radio/checkbox/text/dropdown) | one answer per cell: row_id and column_id (plus value for text grids) |
| NPS / rating | one answer: choice_id (the chosen point) |
| Constant sum, slider | one answer per row: choice_id and value (the number) |
| Date box | value in the question's format: dd/MM/yyyy, HH:mm (24-hour), or dd/MM/yyyy HH:mm (MM/dd/yyyy for US date order) |
| Ranking | one answer per ranked option (choice_id) |
| Map | pins: [{ "latitude", "longitude", "comment"? }] |
| File upload | use the multipart request (see below) |
Examples
Add a completed response
POST {base_url}/surveys/1718994/responses
Authorization: Basic ZXhhbXBsZV90b2tlbjpleGFtcGxlX3NlY3JldA==
Content-Type: application/json{
"status": "completed",
"questions": [
{ "id": 26210001, "answers": [ { "choice_id": 5500001 } ] },
{ "id": 26210002, "answers": [
{ "choice_id": 5500010 },
{ "choice_id": 5500012 },
{ "choice_id": 5500099, "value": "Heard from a friend" }
] },
{ "id": 26210003, "answers": [ { "value": "Loved the onboarding flow." } ] },
{ "id": 26210004, "answers": [ { "choice_id": 5500030 } ] }
]
}A radio question, a checkbox question (two options plus an “other” with text), a single text box (value only), and an NPS question.
Response — 201 Created
{ "id": 88123456 }with header Location: /surveys/1718994/responses/88123456.
Partial response with a resume link
{
"status": "partial",
"generate_save_and_continue_link": true,
"questions": [
{ "id": 26210001, "answers": [ { "choice_id": 5500001 } ] }
]
}Import a historical response
{
"status": "completed",
"completion_actions": "none",
"date_started": "2025-11-02T09:14:00Z",
"date_ended": "2025-11-02T09:19:30Z",
"unique_id": "crm-12345",
"questions": [ { "id": 26210001, "answers": [ { "choice_id": 5500001 } ] } ]
}completion_actions: none records the response without sending emails or triggering webhooks, integrations or AI. Use no_email instead if you still want webhooks and integrations to run.
Store variables
{
"status": "completed",
"questions": [ /* … */ ],
"variables": [
{ "name": "source", "value": "api-import" },
{ "name": "tier", "value": "enterprise" }
]
}What gets returned
Every successful insert returns 201 Created with a Location header pointing at the new response. The body depends on ?return=:
return | Body |
|---|---|
minimal (default) | { "id": <responseId> } |
full | the full response, with pages, questions and answers |
none | empty — read the id from the Location header |
Status codes
| Code | Meaning |
|---|---|
| 201 | The response was added |
| 400 | The request was invalid — check the returned error details (e.g. an answer that breaks the question's format, length, selection or total rules) |
| 403 | Your API key can't add responses to this survey |
| 404 | The survey doesn't exist |
| 409 | The response couldn't be added (for example, your account's response allowance has been reached, or an attached file couldn't be saved). Nothing was stored — you can safely retry |
Good to know
- A completed response counts towards your account's response allowance.
- Only the answers you send are validated (format, range, selection, totals). “Required” rules aren't enforced, so partial responses and imports are accepted.
translation_idis the survey's numeric translation id, not a language code (e.g.en).- For map questions, send
pinsinstead of the usual answer fields. - Selection is expressed only by including a
choice_idin theanswersarray — there's nois_selectedfield to set. - Sending the same
choice_idtwice, or the samerow_id+column_idpair twice, returns a 400 rather than being silently deduplicated. - A 403 doesn't only mean a permissions problem — it's also returned if your account's plan doesn't include response inserts via the API at all. The error message tells you which case applies; contact SmartSurvey Support if you hit the plan-tier one.
Question type examples
Dropdown, list, single image, and the score/rating variants (CSAT, CES, eNPS, star/smiley/thumb ratings) all use the same shape as the Radio example above — one answer, choice_id only.
Matrix, constant sum and slider
{
"status": "completed",
"questions": [
{ "id": 26210010, "answers": [
{ "row_id": 5501001, "column_id": 5501010 },
{ "row_id": 5501002, "column_id": 5501012 }
] },
{ "id": 26210011, "answers": [
{ "choice_id": 5502001, "value": "60" },
{ "choice_id": 5502002, "value": "40" }
] },
{ "id": 26210012, "answers": [ { "choice_id": 5503001, "value": "7" } ] }
]
}Matrix — checkbox, text grid and dropdown cells
The example above shows a single-answer-per-row matrix. Checkbox matrices work the same way but allow more than one column_id per row_id; text-grid and dropdown matrices add a value:
{
"status": "completed",
"questions": [
{ "id": 26210016, "answers": [
{ "row_id": 5507001, "column_id": 5508001 },
{ "row_id": 5507001, "column_id": 5508002 },
{ "row_id": 5507002, "column_id": 5508010, "value": "Great support team" },
{ "row_id": 5507003, "column_id": 5509005, "value": "5509005" }
] }
]
}Row 5507001 is a checkbox row with two columns ticked. Row 5507002 is a text-grid cell — value is the typed text. Row 5507003 is a dropdown-matrix cell — value is the chosen option's id, not its display text.
Ranking
{
"status": "completed",
"questions": [
{ "id": 26210013, "answers": [
{ "choice_id": 5504001 },
{ "choice_id": 5504002 },
{ "choice_id": 5504003 }
] }
]
}Rank is the position in the array, not a field you send — 5504001 is ranked 1st, 5504002 2nd, and so on. There's no explicit rank number.
Multiple textboxes, multi-date range and AI Follow-Up
For a question with more than one input (e.g. "First name" / "Last name", or a date range), each input is its own answer: choice_id identifies which input, value is what was typed.
{
"status": "completed",
"questions": [
{ "id": 26210014, "answers": [
{ "choice_id": 5505001, "value": "Alice" },
{ "choice_id": 5505002, "value": "Smith" }
] }
]
}An AI Follow-Up question uses the same shape — the initial answer, then each generated follow-up question/answer pair, all keyed by their own choice_id:
{
"status": "completed",
"questions": [
{ "id": 26210015, "answers": [
{ "choice_id": 5506001, "value": "I loved the onboarding flow" },
{ "choice_id": 5506002, "value": "Why do you say that?" },
{ "choice_id": 5506003, "value": "Because it only took two minutes" }
] }
]
}Comment box
A comment box can be attached to almost any question type. It's just another answer cell, identified by the comment option's choice_id, alongside the question's normal answer(s):
{
"status": "completed",
"questions": [
{ "id": 26210017, "answers": [
{ "choice_id": 5510001 },
{ "choice_id": 5510002, "value": "Extra thoughts here" }
] }
]
}Date box
value must match the question's configured format:
{
"status": "completed",
"questions": [
{ "id": 26210018, "answers": [ { "value": "25/12/1990" } ] }
]
}- Date only:
dd/MM/yyyy(orMM/dd/yyyyfor US-format surveys) — e.g."25/12/1990" - Time only:
HH:mm(24-hour) — e.g."14:30" - Date and time:
dd/MM/yyyy HH:mm— e.g."25/12/1990 14:30"
Map question
{
"status": "completed",
"questions": [
{ "id": 26214630, "answers": [ {
"pins": [
{ "latitude": 51.5074, "longitude": -0.1278, "comment": "Head office" },
{ "latitude": 53.4808, "longitude": -2.2426 }
]
} ] }
]
}Latitude must be between −90 and 90, longitude between −180 and 180.
File uploads (multipart)
Send the same JSON in a payload form field, and attach each file as a part named question_<questionId> (repeat the name for multiple files on one question):
POST {base_url}/surveys/1718994/responses
Authorization: Basic ZXhhbXBsZV90b2tlbjpleGFtcGxlX3NlY3JldA==
Content-Type: multipart/form-data; boundary=----X------X
Content-Disposition: form-data; name="payload"
{"status":"completed","questions":[{"id":26210020,"answers":[]}]}
------X
Content-Disposition: form-data; name="question_26210020"; filename="cv.pdf"
Content-Type: application/pdf
%PDF-1.7 ...binary...
------X--
