---
title: "List responses"
method: GET
path: "/api/v3/responses"
tags: ["V3 Responses"]
---

# List responses

`GET /api/v3/responses`

## Request

- Base URL: `https://app.formbricks.com`
- URL: `https://app.formbricks.com/api/v3/responses`
- Auth: one of:
  - API key in cookie `next-auth.session-token`
  - API key in header `x-api-key`
  - HTTP bearer

Returns responses for a workspace, newest first. Session cookie, `x-api-key`, or a Bearer token, with read access.

**Scoping.** `workspaceId` is required, as on every v3 collection read. Add `surveyId` to narrow to one survey — the common case, and the one the storage layer is indexed for (`(surveyId, createdAt)`). A workspace-wide list has to reach responses through their surveys and is correspondingly slower, so pass `surveyId` whenever you know it. `contactId` narrows to one respondent.

**Pagination is keyset**, on `(createdAt, id)`. The `cursor` is opaque and bound to the sort order and the filter set it was issued for; changing either invalidates it. `meta.nextCursor` being `null` is the only end-of-collection signal — do not infer the end from a short page.

`id` is there purely as a tie-breaker, and it makes the order **total**, so no row is ever skipped or repeated across pages. What it is not is a finer-grained clock: `createdAt` is stored to millisecond precision, so responses sharing a millisecond — everything written in one bulk insert, for instance — come back in an order that is stable and repeatable but is not their true creation order. Do not read the sequence within a millisecond as meaningful.

**Filters are allow-listed**, and each one on its own is either served by an index or bounded by one. `filter[finished][eq]` and `filter[language][in]` additionally require `surveyId` or `contactId`, because both are heap residuals that are only bounded when the scan is anchored to one survey or one contact; sending either without such a scope returns **400**.

Be aware that **combining** a `filter[createdAt]` bound with `filter[finished][eq]` is the one case no single index covers: the ordered scan uses `(surveyId, createdAt)` and `finished` stays a heap residual, so a page whose matches are sparse reads far more rows than it returns. Prefer narrowing by `surveyId` and a tight `createdAt` window, and treat that combination as the slow path until a covering index exists.

**What this endpoint deliberately does not filter on:** individual answers, hidden-field values, submission metadata (`source`, `url`, `country`, `browser`, `os`, `deviceType`), contact attributes, quotas, and tags. Each is a JSON path or an unindexed join on the largest table in the database, where the honest outcome is a timeout rather than a slow query. The in-app dashboard does offer these, so this endpoint is knowingly behind it; closing the gap needs index work and is tracked separately rather than quietly omitted.

## Query parameters

- `workspaceId` string, cuid2, required
- `limit` integer
- `cursor` string
- `surveyId` string, cuid2
- `contactId` string, cuid2
- `includeTotalCount` boolean
- `filter[createdAt][gte]` string, date-time
- `filter[createdAt][gt]` string, date-time
- `filter[createdAt][lte]` string, date-time
- `filter[createdAt][lt]` string, date-time
- `filter[finished][eq]` boolean
- `filter[language][in]` string[]
- `filter[id][in]` string[]
- `sortBy` '-createdAt' | 'createdAt'

## Response `200`

Responses retrieved successfully

- object
  - `data` ResponseListItem[], required
    - `id` string, cuid2, required: Response identifier.
    - `surveyId` string, cuid2, required: The survey this response belongs to.
    - `surveyName` string, required: The survey's current name, denormalized into the payload so a consumer listing responses need not resolve survey names separately.
    - `workspaceId` string, cuid2, required: The owning workspace, resolved through the survey. Responses carry no workspace column of their own; this is a derived field.
    - `createdAt` string, date-time, required: When the response was created. **Server-owned** — it cannot be supplied on create or changed by a patch. This is the AIP-148 output-only convention, and it is deliberate on two counts: monthly response metering counts rows by `(surveyId, createdAt)`, and a client-chosen `createdAt` can insert rows into the middle of another consumer's already-paginated stream. Backdating remains available on v1/v2; a dedicated import path is future work.
    - `updatedAt` string, date-time, required: When the response was last modified. Server-owned. Neither filterable nor sortable — it has no index, and being mutable it cannot anchor a pagination cursor.
    - `finished` boolean, required: Whether the respondent reached an ending.
    - `endingId` string, nullable, required: The ending card the respondent reached. `null` for unfinished responses.
    - `language` string, nullable, required: The survey language this response was collected in, as a survey language code (not necessarily a BCP-47 locale — `default` is a legitimate value). `null` when the survey is single-language or no language was stamped.
    - `durationSeconds` number: Total seconds the respondent spent, summed from per-element timing and **excluding** the stored `_total` bucket, which the server maintains alongside real element ids and which would otherwise be double-counted. Absent when the submission carried no timing. Summing rather than reading `_total` is deliberate: the stored bucket is only written when a response is finished, so reading it would leave every partial response without a duration even when it carries per-element timing. This is also why the value can differ from the reserved `durationSeconds` catalog entry, which does read the bucket and rounds to whole seconds — that entry is not projected into `embeddedData[]`, so the two never appear side by side.
    - `resolution` ResponseResolution, required: Receipt describing how `answers[]` and `embeddedData[]` labels were produced. It exists so a consumer can tell whether the labels it is reading are the wording the respondent actually saw.
      - `labelPolicy` 'currentSurveyDefinition', required: Where labels came from. Today the only value is `currentSurveyDefinition`: labels are resolved at **read time** against the survey as it stands now. Nothing about the survey is snapshotted when a response is written and there is no survey-version model, so a response collected under an older headline reads back under today's wording — text the respondent may never have seen. Typeform, SurveyMonkey, Qualtrics, Google Forms and Jotform all behave this way, so this is the industry norm rather than a shortcut. Compare `surveyUpdatedAt` against the response's `createdAt` to detect that the definition moved after collection. If a write-time label snapshot ever ships, a second value `asAsked` is added here and consumers branch on it — treat this as an open enum.
      - `labelsLanguage` string, nullable, required: The language the labels in this payload were resolved in. Follows the response's `language` when it is set and the survey has that language enabled, otherwise the survey's default language. `null` when the survey carries no translations.
      - `surveyUpdatedAt` string, date-time, required: When the survey definition was last modified. Later than the response's `createdAt` means the wording in `elementLabel` may have drifted from what was asked.
    - `answers` ResponseAnswer[], required: One entry per element the respondent reached, in survey order. Empty for a response that recorded no answers.
      - union: One answer, carrying the element's id, its label, its type and its value. `elementType` selects the shape: switch on it rather than probing for which value field is present. Answers are a **typed array**, not a map keyed by element id, because a consumer holding only a response would otherwise see bare ids and have to fetch the survey and join to learn what was asked — a join that is easy to get wrong and that agent clients cannot make cheaply. The array also separates answers from hidden fields and variables, which the stored representation mixes into one flat map. Non-answer data lives in `embeddedData[]`. Several element types share a value shape and therefore a schema — the four numeric scales, the four choice styles, the two composites. All seventeen element types are covered. Only elements the respondent actually reached appear here. Data whose element has since been deleted appears in `unresolved[]` instead.
        - ResponseAnswerText: Free-text answer to an `openText` element.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'openText', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `valueText` string, required: The submitted text, verbatim.
          - `inputType` 'text' | 'email' | 'url' | 'number' | 'phone': The element's configured input type in the current definition. Useful for rendering and for knowing how the value was validated at collection time; the value itself is always returned as a string, including for `number`.
        - ResponseAnswerNumber: Numeric-scale answer. Covers `nps` (0–10), `rating` (configurable range and presentation), `csat` and `ces`.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'nps' | 'rating' | 'csat' | 'ces', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `valueNumber` number, required: The submitted score.
          - `range` object, required: The scale the score was collected on, from the current definition. Returned because a bare `8` is uninterpretable without it, and because scales are editable — a consumer comparing scores across time needs to see that the range moved.
            - `min` number, required
            - `max` number, required
          - `scale` 'number' | 'smiley' | 'star': How the scale was presented. Carried by the element types that configure one — `rating`, `csat` and `ces` — and absent for `nps`, which has no scale presentation.
        - ResponseAnswerBoolean: Acknowledgement answer. Covers `consent` (accepted) and `cta` (clicked through). A `cta` element the respondent skipped has no entry in `answers[]` at all.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'consent' | 'cta', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `valueBoolean` boolean, required: Whether the respondent accepted (`consent`) or clicked through (`cta`). Derived from the stored token, which is why `rawValue` is returned alongside it.
          - `rawValue` string, required: The token as stored — conventionally `accepted` for `consent` and `clicked` for `cta`. Returned because the boolean is a derivation and this is the underlying fact.
        - ResponseAnswerSelection: Choice-style answer. Covers `multipleChoiceSingle`, `multipleChoiceMulti`, `pictureSelection` and `ranking`. See `ResponseValueMatch` for how each selection was resolved and why an unresolvable value is never reclassified as a write-in.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'multipleChoiceSingle' | 'multipleChoiceMulti' | 'pictureSelection' | 'ranking', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `selections` ResponseSelection[], required: The chosen options, resolved against the current definition. Always an array, including for `multipleChoiceSingle`, so consumers need one code path rather than two. For `ranking`, the array is in rank order and each entry also carries an explicit `rank`.
            - `optionId` string, nullable, required: Resolved option id, or the literal `other` for a write-in. `null` when `match` is `unmatched`.
            - `optionLabel` string, nullable, required: Option label in the resolved language. `null` when `match` is `unmatched`.
            - `rawValue` string, required: The value as stored on the response, verbatim and before resolution — always present, and the string to use when rebuilding the stored map. Note what is stored differs by element type: `multipleChoiceSingle`, `multipleChoiceMulti` and `ranking` store the option **label** in the respondent's language, while `pictureSelection` stores the option **id**. `""` occurs when the respondent selected Other and left it blank, and is returned rather than dropped.
            - `match` 'exact' | 'label' | 'other' | 'unmatched', required: How a stored raw value was resolved against the current survey definition. Precedence is fixed and applied in this order: - `exact` — the stored value matched an option **id** in the current definition. - `label` — the stored value matched an option's **label text** (ids are stable, labels are editable and language-dependent, so a label match is weaker evidence). - `other` — the value arrived through the element's **Other** free-text input. Only reported when the element actually has that input enabled and the value was submitted through it. - `unmatched` — no option resolves. The raw value is still returned; it is **not** silently reclassified as `other`, because a *renamed* option is also unmatched text and filing it as a write-in would misattribute the answer.
            - `rank` integer: 1-based rank, present only for `ranking` elements. Array order already reflects the rank; this field makes it explicit so consumers need not rely on ordering.
        - ResponseAnswerDate: Date answer.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'date', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `valueDate` string, required: The submitted date as stored, an ISO-8601 date or date-time string. No `format` is asserted because historical rows were written by several client versions and the stored precision varies; parse defensively.
        - ResponseAnswerFileUpload: File-upload answer.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'fileUpload', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `fileUrls` string[], required: The uploaded files, **as stored** — workspace-relative paths, not absolute URLs, and neither resolved nor signed. A deliberate choice between two things this field could be. Storage writes a relative path and the app's own read paths rewrite it to an absolute URL for display; v3 returns the stored bytes instead, because `answers[]` promises verbatim values a client can write straight back, and an absolute URL is neither what is stored nor what a write accepts. Fetching a file is a separate concern with its own ticket (ENG-513, signed short-lived URLs behind a dedicated endpoint); this field identifies the file, it does not serve it. Not publicly fetchable in any case: access follows the same authorization as the response, and deleting the response deletes the underlying files.
          - `fileCount` integer: Convenience count of `fileUrls`, so a list consumer need not materialize the array.
        - ResponseAnswerBooking: Scheduling answer for a `cal` element. Only the fact of the booking is recorded on the response; the meeting itself lives in the scheduling provider and is not proxied by this API.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'cal', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `booked` boolean, required: Whether the respondent completed a booking.
          - `rawValue` string, required: The token as stored, verbatim — conventionally `booked`. Required, like the equivalent field on `consent` and `cta`, because `booked` is a derivation and this is the underlying value a client needs to rebuild the stored map.
        - ResponseAnswerMatrix: Matrix answer — one selected column per answered row.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'matrix', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `rows` object[], required: One entry per row the respondent answered. Rows left blank are omitted rather than returned with a null column. Both sides of a matrix cell need resolving against the current definition, so each entry reports its own `match` — see `ResponseValueMatch`.
            - `rawKey` string, required: The stored map key for this row, verbatim. Matrix answers are stored keyed by the **localized row label** in the respondent's language, not by row id — so this is the string to use when rebuilding the stored object, and it is not necessarily equal to `rowLabel`, which is resolved in the *current* definition's language.
            - `rowId` string, nullable: Row id resolved from the current definition, or `null` when the stored key matches no current row. Derived, never stored.
            - `rowLabel` string, required: Row label in the resolved language. Falls back to `rawKey` when the row no longer resolves.
            - `columnId` string, nullable: Column id resolved from the current definition, or `null` when it no longer resolves. Derived, never stored.
            - `columnLabel` string, nullable, required: Column label in the resolved language. `null` when `match` is `unmatched`.
            - `rawValue` string, required: The selected column as stored, verbatim — the localized column label, not a column id. This is the value to use when rebuilding the stored object.
            - `match` 'exact' | 'label' | 'other' | 'unmatched', required: How a stored raw value was resolved against the current survey definition. Precedence is fixed and applied in this order: - `exact` — the stored value matched an option **id** in the current definition. - `label` — the stored value matched an option's **label text** (ids are stable, labels are editable and language-dependent, so a label match is weaker evidence). - `other` — the value arrived through the element's **Other** free-text input. Only reported when the element actually has that input enabled and the value was submitted through it. - `unmatched` — no option resolves. The raw value is still returned; it is **not** silently reclassified as `other`, because a *renamed* option is also unmatched text and filing it as a write-in would misattribute the answer.
        - ResponseAnswerComposite: Composite answer whose value is a set of labelled sub-fields. Covers `address` and `contactInfo`. Stored as a positional array of strings, which is why every slot is reported.
          - `position` integer, required: 1-based position of the element in the current survey definition, so a consumer can present answers in survey order without fetching the survey. Elements the respondent never reached are absent from `answers[]` entirely rather than present-and-empty.
          - `elementId` string, required: Stable element id, as authored on the survey.
          - `elementType` 'address' | 'contactInfo', required: The element's type in the current survey definition. Matches the `type` of the corresponding `SurveyElement`.
          - `elementLabel` string, required: The element's headline, resolved in `resolution.labelsLanguage`. Read at request time from the current definition — see `ResponseResolution` for what that means for older responses.
          - `durationSeconds` number: Seconds the respondent spent on this element. Converted from the stored per-element time-to-complete, which is recorded in milliseconds. This telemetry is reported by the client and is therefore not trustworthy input: treat it as an indication rather than a measurement. Absent when the submission carried no timing for this element. The bounds hold on **every** row, including ones collected before the write-side clamp shipped. The stored representation is deliberately unbounded so that historical data still parses, and a row written then can hold a negative value or a tab left open for days; those are clamped into range on read rather than returned as-is, because a schema a real row violates is worse than a slightly blunted outlier. So `86400` means "at least 24 hours", not exactly.
          - `fields` object[], required: The element's sub-fields, **every slot, in storage order**, including ones the respondent left blank (`valueText: ""`). Blanks are returned rather than omitted because the stored value is a positional fixed-length array — `address` has 6 slots, `contactInfo` has 5 — so dropping an empty slot would shift every later value onto the wrong field and make the stored array impossible to rebuild.
            - `slot` integer, required: 0-based index of this sub-field in the stored array. Reconstruct the stored value by ordering on this and taking `valueText`.
            - `fieldId` 'addressLine1' | 'addressLine2' | 'city' | 'state' | 'zip' | 'country' | 'firstName' | 'lastName' | 'email' | 'phone' | 'company', required: Stable sub-field id. `address` uses `addressLine1`, `addressLine2`, `city`, `state`, `zip`, `country` in that order; `contactInfo` uses `firstName`, `lastName`, `email`, `phone`, `company`.
            - `fieldLabel` string, required: Sub-field label in the resolved language.
            - `valueText` string, required: The submitted value, verbatim. `""` when the respondent left it blank.
    - `embeddedData` ResponseEmbeddedDatum[], required: Hidden fields, variables and auto-captured context, as one collection. Empty when the response carries none.
      - `key` string, required: The field's **name** — what an author calls it, and the key `embeddedData` on a write accepts. Not the storage key. A hidden field happens to be stored under its name and a variable under its cuid, and that split is a property of the storage layout rather than of the field; exposing it would publish an internal id and make the writable and readable views of one field disagree on how to address it. **Unique per `kind`, not across the collection.** A survey created before the reserved names were enforced can declare a hidden field called `country`, and the auto-captured `country` still exists — so the same name can appear once as `ingested` and once as `reserved`. That set is finite and no longer growing: a new declaration may no longer take a reserved name, or the name of a variable or hidden field the survey already has. Key on `(key, kind)` rather than `key` alone, or read the pair you care about.
      - `kind` 'ingested' | 'computed' | 'reserved', required: Provenance of the value: - `ingested` — supplied by the caller or the embedding page (hidden fields). - `computed` — derived during the submission by survey logic (variables). - `reserved` — auto-captured context from the submission environment (for example `country`, `deviceType`), drawn from the Embedded Data field catalog.
      - `type` 'string' | 'number' | 'boolean' | 'date', required: Declared type of `value`, so a consumer need not infer it. `computed` entries are only ever `string` or `number`, because survey variables are typed that narrowly.
      - `label` string, required: Human-readable name for the key, in the resolved language where one exists.
      - `value` union, required: The value, matching `type`. `date` values are ISO-8601 strings. Always a scalar. A legacy row can hold an array or an object under a declared field's key — the ingest contract refuses those now, but older rows have them — and such a value resolves to nothing rather than being coerced, so the entry is omitted here and reported in `unresolved[]` with the bytes intact. Nothing is silently dropped, and no `type` would describe an array anyway. There is no `null` member: a declared key that resolves to nothing is **omitted** from the collection rather than carried with a null. So `embeddedData[]` enumerates what the response actually holds, not what the survey declares — a survey with twelve declared fields and two filled in yields two entries. A field with a default value is never unset, since the default is the fallback before the key is considered missing.
        - string
        - number
        - boolean
    - `unresolved` ResponseUnresolvedEntry[], required: Stored data whose element or key no longer exists in the survey definition. Empty in the normal case.
      - `key` string, required: The key as stored on the response. For `elementNotInSurvey` it is a former element id or hidden-field name; for `variableNotInSurvey` a variable's cuid, since that map is keyed by id rather than by name; and for `valueShapeMismatch` the id or name of the element or declared field that *does* still exist — that reason means the key resolved and the value did not.
      - `rawValue` union, required: One stored answer or field value, in the four shapes the v3 contract can carry: a string, a number, a list of strings, or a string-to-string map. Declared once and referenced by `ResponseDataMap` and `ResponseUnresolvedEntry.rawValue`, so the two places that publish stored JSON cannot drift apart. A stored value outside these shapes (a legacy JSON `null`, an array with non-string items, a map with non-string values) is not published at all rather than reaching a client as a body this contract would reject.
        - string
        - number
        - string[]
        - object
      - `reason` 'elementNotInSurvey' | 'variableNotInSurvey' | 'valueShapeMismatch', required: Why the entry could not be resolved: - `elementNotInSurvey` — nothing in the current definition claims this key. It covers a deleted element **and** a deleted hidden field, because the two cannot be told apart: an answer is stored under its element id and a hidden field under its name, in one shared map, and storage keeps no record of which kind a vanished key used to be. - `variableNotInSurvey` — no variable with this id exists in the current definition. Variables *are* distinguishable, because they live in their own map keyed by cuid rather than sharing the answer map. - `valueShapeMismatch` — the key resolves to a current element **or a declared Embedded Data field**, but the stored value's shape cannot be read as an answer of that element's type (for example a string where the element expects a selection list). Signals element-type churn rather than deletion.
    - `tags` ResponseTag[], required: Tags applied to this response, as `{ id, name }` references. Empty when the response is untagged.
      - `id` string, cuid2, required
      - `name` string, required: Tag label as shown in the app.
  - `meta` ResponseListMeta, required: The list `meta` for responses — pagination plus a bounded, opt-in total. Both counting fields are `required` but nullable, so `includeTotalCount=false` answers `null` rather than omitting them.
    - `limit` integer, required: The page size actually applied. Carries no `maximum`: it echoes what the server used, it does not bound what may be asked for. The request-side bound is the `limit` query parameter on the operation itself and differs per collection — read it there. A shared description cannot state it without being wrong for some of the operations that compose this base.
    - `nextCursor` string, nullable, required: Opaque cursor for the next page. `null` when there are no more results — the only reliable end-of-collection signal, since the server may return fewer items than `limit` without the collection being exhausted. Pass it back verbatim: the encoding is deliberately unspecified and may change without notice, so a client that decodes or constructs one is relying on something this contract does not promise.
    - `totalCount` integer, nullable, required: Responses matching the current scope and filters across all pages, **counted only up to 10 000**. Exact below that; at the cap the value is exactly `10000` and means "at least 10 000", which `totalCountRelation` states explicitly. `null` unless `includeTotalCount=true`. The cap is not timidity — an exact count over this table grows superlinearly with the data while a capped one stays flat, so an uncapped total is the one part of a page whose cost is unbounded. Read `totalCountRelation` rather than testing for the magic number.
    - `totalCountRelation` 'eq' | 'gte' | 'null', nullable, required: How to read `totalCount`: `eq` when it is exact, `gte` when the 10 000 cap was reached and it is a lower bound, `null` when `includeTotalCount=false`. This is the same eq/gte convention Elasticsearch uses for `hits.total.relation`, so a consumer can render "10,000+" honestly instead of claiming a precise figure it does not have.

## Other responses

- `400`: Bad Request — invalid or unrecognized query parameters. Covers an unknown `filter[...]` key, a filter value of the wrong type, `filter[id][in]` over 100 ids, a `cursor` that does not match the requested sort order or filter set, and `filter[finished][eq]` or `filter[language][in]` sent without `surveyId` or `contactId`. Date bounds are also validated as a pair: at most **one lower bound** (`gte` xor `gt`) and at most **one upper bound** (`lte` xor `lt`), and the lower bound must not fall after the upper one. Sending both forms of the same bound is rejected rather than resolved by a precedence rule nobody can guess.
- `401`: Not authenticated (no valid session or API key).
- `403`: Forbidden — no workspace access, or resource does not exist (404 not used; avoids existence leak).
- `413`: Payload Too Large — the request body exceeds the 2 MB limit.
- `429`: Rate limit exceeded.
- `500`: Internal Server Error.

## Changes

- **2026-10-28** `84820a01e550`: 18 warning
  - added the new `chart_in_use` enum value to the `code` response property for the response status `400`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `401`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `403`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `413`
  - …14 more
- **2026-10-27** `aad5dc1d8236`: 12 warning
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `400`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `401`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `403`
  - added the new `creatives_not_entitled` enum value to the `code` response property for the response status `413`
  - …8 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/formbricks/apis/formbricks-api-v3/changes/api/v3/responses/get.md)

---

[API](https://skmtc.dev/formbricks/apis/formbricks-api-v3.md) - [All operations](https://skmtc.dev/formbricks/apis/formbricks-api-v3/llms.txt) - [OpenAPI document](https://skmtc.dev/formbricks/apis/formbricks-api-v3/revisions/25335c959a13?raw)
