The examples on this page use the EU host. If your project lives in another region, replace
https://api.gleap.io with your region’s host. API tokens are per project and only valid in the project’s region.{id} below is the survey’s Gleap id (the _id returned by GET /v3/engagement/surveys). The id you pass to Gleap.showSurvey is the survey’s SDK id (actionType) — a different value.
Every endpoint is project-scoped and checks the same survey permissions as the dashboard (viewers can read, members and admins can edit).
Surveys
Delete a survey
DELETE /v3/engagement/surveys/{id} deletes the survey at once. Everything stored for it follows in the background, usually within a minute and at the latest after about ten: every response (including the files respondents uploaded, and the survey tickets of a survey created before Surveys 2.0), its published versions, stats, analytics events and search entries. Conversations started from a response stay (without the link to it). Live email campaigns that send the survey are paused right away (their pending sends are dropped) and kept, without the survey. GET /v3/engagement/surveys/{id}/delete-preview returns what a deletion affects besides the survey’s own data: { liveEmailCampaigns: [{ id, name }], legacyTickets }. This cannot be undone: export the responses first if you need them.
Create a draft
Save the draft
{ definition, warnings }. Drafts may contain invalid logic — warnings lists what publishing would reject. Saving the draft of a live survey doesn’t change what respondents see.
Validate
POST /validate with { "definition": { … } } returns { ok, errors: [{ path, code, message }] } and saves nothing.
Publish
POST /publish validates the draft, stores it as the next immutable version and makes it the version respondents see. Invalid drafts return 422 with errors. Publishing doesn’t start the survey in your app: that is the survey’s status (live shows it to the in-app audience, Share → In the app in the dashboard), or send { "goLive": true } to publish and start it in one call. The survey page and emails use the published version whatever the status.
Survey page settings
PUT /page takes:
slug is unique per project (^[a-z0-9-]{2,60}$). access is anyone or personal_links_only. afterSubmit.mode is ending or redirect.
Results
Stats
GET /v3/engagement/surveys/{id}/stats?from=2026-09-01&to=2026-09-30&version=3
Computed from stored counters, so it is cheap at any volume. nps (score and distribution) is present when the survey has an NPS question; perBlock is keyed by answer key, edges counts the paths between blocks (from>to).
Analytics
GET /v3/engagement/surveys/{id}/analytics?from=2026-09-01&to=2026-09-30 — views, starts, submissions, the question funnel with drop-off, timing, breakdowns and the previous period for comparison, from survey events. See Survey analytics.
Responses
GET /v3/engagement/surveys/{id}/responses
Returns
{ responses: [...], nextCursor }, newest first. Response objects are described in Survey definition → Responses.
Compatibility for existing pollers. Integrations that page through this endpoint with
skip / limit keep receiving the previous shape — an array of { _id, formData, session, createdAt, updatedAt }, where formData holds the answers keyed by answer key (for a survey created before Surveys 2.0: by its old field names). Switch to cursor to get the new fields (status, path, version, channel, themes).Survey answers on the ticket API (until January 5, 2027)
Before Surveys 2.0 every answer was a ticket of typeSURVEY. Until January 5, 2027 the ticket API keeps returning them, without creating tickets:
GET /v3/tickets?type=SURVEY,GET /v3/tickets/export?type=SURVEYandGET /v3/tickets/csv-export?type=SURVEYlist survey answers in the ticket shape, newest first (skip/limit,outbound,sessionand date filters work). An answer from before the upgrade is its original ticket (same_id,bugId,formData); a newer one is a ticket view with_id= the response id,formDataunder the old field names (choices as their text), the contact’s fields insession,createdAt= when it was completed, andsurveyResponse. Merged pages go up to 25,000 rows deep.GET /v3/sessions/{sessionId}/activities?surveyResponses=includeadds the contact’s survey responses to its tickets;surveyResponses=onlylists only them (withsurveyName,outboundandresponseStatus).
type=SURVEY returns tickets only. Move to GET /v3/engagement/surveys/{id}/responses, the survey webhooks or automations before then.
Reach out to a respondent
POST /v3/engagement/surveys/{id}/responses/{responseId}/reach-out
channel is messenger or email (with an optional subject); message is plain text or a TipTap document. Gleap starts a normal conversation with the contact, links it to the response and returns { ticketId, ticketShareToken }.
AI insights
GET /insights returns the links as links and per theme as themes[].links, each with the ticket’s number, title, status and type or the Kai Code session’s title and status. Links to deleted tickets or sessions are left out.
Insights are generated on demand: GET /insights always answers at once with what is stored. When responses came in since the last update and that update is more than 5 minutes old, the read also starts one update in the background (tagging new answers with themes, recounting, and rewriting the summary after 25 newly tagged answers or 10% more responses). generation tells you its state:
status is updating. Without new responses, reading the insights uses no AI. Each project has a daily budget for survey AI (2,000 answers tagged and 20 summaries or theme lists a day); when it is used up, capped is true and updates resume at resumesAt (the next midnight UTC). A survey nobody opens is never analyzed.
POST /insights/ask: