The response and webhook payload
Every answer comes with its question id, reference, type, title, raw value and readable text, in the API and in webhooks.
Every plan
A response from the API
{
"id": "r_…",
"form_id": "f_…",
"status": "complete",
"submitted_at": "2026-10-26T10:04:31.000Z",
"started_at": "2026-10-26T10:02:10.000Z",
"duration_ms": 141000,
"score": 3,
"ending_id": "s_…",
"tags": ["follow up"],
"respondent": { "name": "Ada Lovelace", "email": "ada@example.com" },
"hidden": { "utm_source": "newsletter" },
"meta": { "device": "mobile", "country": "GB", "referrer": null },
"answers": [
{ "question_id": "s_…", "ref": "nps", "type": "nps", "title": "How likely are you to recommend us?", "value": 9, "text": "9" },
{ "question_id": "s_…", "ref": "plan", "type": "multiple_choice", "title": "Which plan are you on?", "value": { "ids": ["c_…"] }, "text": "Pro" }
],
"followups": [
{ "question_id": "s_…", "ref": "feedback", "question": "What would have made it great?", "answer": "Faster checkout." }
]
}The webhook body
Webhooks send the same answers, wrapped with the event and the form:
{
"event": "response.completed",
"form": { "id": "f_…", "title": "Customer feedback" },
"response": {
"id": "r_…",
"submitted_at": "2026-10-26T10:04:31.000Z",
"duration_ms": 141000,
"score": 3,
"hidden": { "utm_source": "newsletter" },
"answers": [ … ],
"followups": [ … ]
}
}Reading answers
- Use
textwhen you want something readable for any question type. - Use
valuefor the raw answer: a string, number or boolean;{ "ids": [...], "other": "…" }for choices;{ "files": [...] }for uploads; fields by name for contact info and address;{ "rows": {...} }for a matrix;{ "payment": {...} }and{ "booking": {...} }for payments and bookings. - Match answers by
ref(set in each question's reference) so rewording a question doesn't break your code. - Only questions the respondent saw are included.