Add a webhook under Settings → Apps → Webhooks and pick the survey events you need. Responses no longer create tickets, so survey integrations use these events instead of ticket.created.
Events
Event | When | Default |
|---|---|---|
| A respondent reached an ending. | On for new webhooks |
| A question was answered (the response may still be in progress). High volume — one event per answer. | Opt-in |
| A response stopped without reaching an ending: no new answer for 30 minutes. | Opt-in |
A response sends survey.response.partial at most once. If the person comes back and finishes, survey.response.completed follows.
Payload
Answers are keyed by each question's answer key, so payloads stay stable when you reword or reorder questions.
{
"event": "survey.response.completed",
"data": {
"response": {
"id": "rsp_4kq9X2mT7vB1nR8sLp3Z",
"status": "completed",
"version": 3,
"answers": { "nps_score": 4, "detractor_reason": "Slack sync stopped twice this week" },
"path": ["q_nps", "q_detractor", "end_thanks"],
"endingId": "end_thanks",
"channel": "web",
"fields": { "plan": "pro" },
"language": "en",
"pageUrl": "https://app.yourcompany.com/settings",
"startedAt": "2026-10-06T09:12:03.000Z",
"completedAt": "2026-10-06T09:12:41.000Z"
},
"survey": { "id": "q7x2kd", "name": "Post-onboarding NPS", "version": 3 },
"contact": { "userId": "user_1842", "name": "Ada Lovelace", "email": "[email protected]" }
}
}survey.idis the survey's SDK id — the value you pass toGleap.showSurvey.contactisnullfor anonymous respondents.Answer values: numbers for scales and
number, the choice id forsingle, an array of choice ids formulti,true/falseforyesno, strings for text inputs andYYYY-MM-DDfor dates. "Other" answers are{ "other": "…" }. See Survey definition.survey.response.answeredcarries the response as it is at that moment (status: "in_progress"), including all answers so far.
Migrating from ticket webhooks
Before Surveys 2.0, every survey response created a ticket of type Survey, and integrations listened to ticket.created filtered to surveys.
ticket.created that received survey tickets before — filtered to the Survey type, or without a type filter — keep receiving a ticket-shaped payload for every completed response: formData keyed by the old question names (migrated surveys) or answer keys with choices as their label text, session with the same contact fields as before, and surveyResponse with the response id. Move those integrations to survey.response.completed before then.The ticket-type filter of a webhook only narrows ticket and message events, so a webhook filtered to Survey also receives the survey.response.* events you add to it.
To act on responses inside Gleap — email the respondent, open a ticket, notify a teammate — use a survey automation.
Mapping from the old payload:
Old ( | New ( |
|---|---|
|
|
|
|
ticket |
|
|
|

