> ## Documentation Index
> Fetch the complete documentation index at: https://formhug.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# List entries of a form

> Returns entries of a form owned by the current user, paginated by cursor.

Order by `serial_number` ascending by default, or pass `sort`. Every form field
appears as a top-level key on each entry under its `api_code`; the JSON value type
follows the field's `type` (see the **Entry** schema).

Optionally filter with `filter`: a URL-encoded JSON array of conditions, all ANDed
together (see the **FilterCondition** schema). `pagination.total` reflects the
filtered count.

**Required scope:** `entry:read`.




## OpenAPI

````yaml /api-reference/openapi.yaml get /api/v1/forms/{form_token}/entries
openapi: 3.0.1
info:
  title: FormHug API V1
  version: v1
  description: |
    FormHug public REST API. All request/response keys are snake_case.

    Successful response:

    ```json
    {
      "data": { ... }
    }
    ```

    Paginated response:

    ```json
    {
      "data": [ ... ],
      "pagination": {
        "total": 123,
        "next_cursor": "NQ=="
      }
    }
    ```

    Error response:

    ```json
    {
      "error": "Human-readable message",
      "error_details": [
        { "attribute": "field_name", "message": "specific error" }
      ]
    }
    ```

    `error_details` only appears for model validation failures.
servers:
  - url: https://formhug.ai
security: []
tags:
  - name: Forms
    description: Form CRUD
  - name: Attachments
    description: >-
      2-step upload for form-element images (theme, rich-text, or field-element
      images). Prepare returns an `upload_id`; consume it in a theme update,
      attachment_commitments, or the form `fields` payload depending on purpose.
  - name: Entries
    description: Entries collected by a form owned by the current user
  - name: Folders
    description: Folder CRUD
  - name: Participated Forms
    description: Forms the current user has submitted to (does not own)
  - name: Published Form Entries
    description: Submit entries to a published form
  - name: Published Forms
    description: Read a published form's public structure for filling
  - name: Entry Attachments
    description: >-
      2-step upload for `attachment` field submissions. Prepare returns an
      `upload_id`; submit it under the attachment field in `field_values` when
      creating the entry.
  - name: Me
    description: Current authenticated user
  - name: Webhooks
    description: Webhook integrations attached to a form
  - name: Form Themes
    description: Read and update a form's visual theme
  - name: Form Settings
    description: >-
      Per-form settings — submission flow, availability, access control,
      presentation
  - name: Field Rules
    description: >-
      Read and replace a form's conditional field-display and post-submission
      redirect rules.
  - name: OAuth
    description: OAuth 2.0 PKCE token issuance and revocation
paths:
  /api/v1/forms/{form_token}/entries:
    parameters:
      - name: form_token
        in: path
        description: Form token
        required: true
        schema:
          type: string
    get:
      tags:
        - Entries
      summary: List entries of a form
      description: >
        Returns entries of a form owned by the current user, paginated by
        cursor.


        Order by `serial_number` ascending by default, or pass `sort`. Every
        form field

        appears as a top-level key on each entry under its `api_code`; the JSON
        value type

        follows the field's `type` (see the **Entry** schema).


        Optionally filter with `filter`: a URL-encoded JSON array of conditions,
        all ANDed

        together (see the **FilterCondition** schema). `pagination.total`
        reflects the

        filtered count.


        **Required scope:** `entry:read`.
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            default: 20
            maximum: 100
          description: Page size (1..100, default 20)
        - name: cursor
          in: query
          required: false
          schema:
            type: string
          description: >-
            Pagination cursor returned in the previous response as
            pagination.next_cursor
        - name: filter
          in: query
          required: false
          schema:
            type: string
          description: >-
            URL-encoded JSON array of filter conditions (see FilterConditions).
            All conditions are ANDed.
        - name: sort
          in: query
          required: false
          schema:
            type: string
          description: >-
            Comma-separated sort keys; prefix a key with `-` for descending.
            Sort over form field api_codes and
            serial_number/created_at/updated_at. Example: `-field_3,field_1`.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - pagination
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Entry'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
        '400':
          description: Invalid filter or sort parameter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorEnvelope'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              examples:
                unauthenticated:
                  value:
                    error: Authentication failed
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: Form not found or not owned by current user
          content:
            application/json:
              examples:
                not_found:
                  value:
                    error: Form not found
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
      security:
        - PersonalAccessToken:
            - entry:read
components:
  schemas:
    Entry:
      type: object
      required:
        - serial_number
        - token
        - created_at
        - updated_at
      description: >+
        A submitted entry. In addition to the fixed fields below, every field of
        the

        parent form appears as a top-level key on the entry under its
        `api_code`. The

        JSON value type for each such key is determined by the corresponding
        field's

        `type`.


        ## Field value shapes


        Each field of the parent form appears as a top-level key on the entry,
        keyed by its

        `api_code`. The JSON shape of the value depends on the field's `type`:


        | Field type (`type`) | Submitted value |

        |---|---|

        | `short_text` | String. The submitted text. |

        | `long_text` | String. Multi-line text. |

        | `radio` | Object `{ value, other_text?, extended_text? }`, or `null`
        when unset. `value` is the `api_code` of the selected choice.
        `other_text` carries the respondent's free-text input and is only
        present when the selected choice has `is_other: true`. `extended_text`
        carries the free-text input for a choice that has `allow_extended_text:
        true`. The two text keys are mutually exclusive per choice (an
        `is_other` choice cannot also enable `allow_extended_text`) and both are
        omitted when blank. On write, a bare string is accepted as shorthand for
        `{ value: <string> }`; `null` clears the field; text keys that don't
        match the selected choice's configuration are ignored. |

        | `checkbox` | Array of `{ value, other_text?, extended_text? }` objects
        with the same per-choice semantics as `radio`. Empty array when nothing
        is selected. At most one element may carry `other_text` (the element
        whose `value` corresponds to the `is_other` choice). On write, `null`
        clears the field; bare strings in the array are accepted as shorthand
        for `{ value: <string> }`; duplicate values are silently de-duplicated
        (first occurrence wins). |

        | `image_radio` | Object `{ value }`, or `null` when unset. `value` is
        the `api_code` of the selected choice. Image choices support neither
        `other_text` nor `extended_text`. On write, a bare string is accepted as
        shorthand for `{ value: <string> }`; `null` clears the field. |

        | `image_checkbox` | Array of `{ value }` objects — `value` is the
        `api_code` of a selected choice. Empty array when nothing is selected.
        On write, `null` clears the field; bare strings in the array are
        accepted as shorthand; duplicate values are silently de-duplicated
        (first occurrence wins). |

        | `dropdown` | Object `{ value, other_text? }`, or `null` when unset.
        Same `value` and `other_text` semantics as `radio`. `dropdown` does not
        support `extended_text`. |

        | `number` | Number. Stored as a float; integer-looking values may
        serialize without a decimal point. |

        | `email` | String — an email address. |

        | `phone` | Object `{ country_id, country_code, number }`. `country_id`
        is an ISO 3166-1 alpha-2 country code (e.g. `"CN"`, `"US"`) and is
        required; `country_code` is the dialing code without `+` (e.g. `"86"`,
        `"1"`) and is optional on write — when omitted it is derived from
        `country_id`; `number` is the local number without the dialing-code
        prefix. |

        | `date` | Naive wall-clock string formatted per the field's
        `precision`: `"YYYY-MM"` (month), `"YYYY-MM-DD"` (day), `"YYYY-MM-DD
        HH:mm"` (minute), `"YYYY-MM-DD HH:mm:ss"` (second). Values are
        interpreted in the form's `timezone` setting. When no `timezone` is
        supplied at creation time, the form uses your account's timezone,
        falling back to `UTC` if that is unset or invalid. |

        | `name` | String — the submitted name. |

        | `url` | String — a URL. |

        | `address` | Object `{ address_line1, address_line2, city, state,
        postal_code, country }`. `country` is an ISO 3166-1 alpha-2 country
        code; `state` is an ISO 3166-2 subdivision code (e.g. `"CA"`, `"NY"`),
        not a localized label. |

        | `rating` | Integer — the chosen rating level (1..`rating_max`). |

        | `nps` | Integer — the selected score (0..10). |

        | `attachment` | Array of objects `{ id: string, name: string, url:
        string, file_size: integer, content_type: string }`. `url` is a signed
        download link valid for 24 hours — refetch the entry to get a fresh link
        rather than caching it; `name` is the original filename. |

        | `audio` | Read-only object `{ id, name, url, file_size, content_type,
        duration }` describing the recording (`url` is a signed download link
        valid for 24 hours; `duration` is the recording length). Null when no
        recording. Submitting a value for an audio field is not supported. |

        | `cascade` | Object `{ level_1: <api_code>, level_2: <api_code>, ... }`
        — one key per level (the field's `levels` setting, default `2`). Each
        value is the `api_code` of the choice selected at that level. |

        | `ranking` | Object `{ <choice_api_code>: <rank> }` — `rank` is a
        positive integer, contiguous starting at `1` for the highest-ranked
        choice. Unranked choices are omitted. |

        | `matrix` | Nested object `{ <statement_api_code>: {
        <dimension_api_code>: <cell_value> }, ... }`. The inner cell value type
        depends on the matrix cell field type. |

        | `likert` | Object `{ <statement_api_code>: [<choice_api_code>, ...]
        }`. The value is always an array — a single-choice answer is wrapped in
        a one-element array. |

        | `time` | Object `{ hour: integer, minute: integer }`, plus `second:
        integer` when the field has `include_second` enabled (e.g. `{ "hour": 9,
        "minute": 5 }`). |

        | `location` | Object `{ longitude: number, latitude: number, address:
        string }`. |

        | `signature` | Read-only string — a signed download URL for the
        signature image, valid for 24 hours. Refetch the entry to obtain a fresh
        link rather than caching it. Submitting a value for a signature field is
        not supported. |

        | `matrix_rating` | Nested object `{ <statement_api_code>: {
        <dimension_api_code>: <integer> } }`. The inner integer is the chosen
        rating level (1..`rating_max`). |

        | `table` | Array of row objects `[{ <dimension_api_code>: <cell_value>,
        ... }]`. The inner cell value type depends on each dimension's field
        type. |

        | `product` | Array `[{ api_code, number, specification? }]`.
        `specification` is present when the goods item has dimensions; it is an
        object of `{ <dim_api_code>: <option_api_code> }`. |

        | `booking` | Array of reservations. On write: `[{ api_code,
        scheduled_at, end_at?, number? }]` — `api_code` is the reservation item;
        `scheduled_at` (and `end_at`) are ISO8601 date-time strings; `number`
        defaults to 1. For a weekly-schedule item send `scheduled_at` on the
        target day. For a per-day-of-week time-slot item send `scheduled_at` =
        day + slot start and `end_at` = day + slot end, matching one of the
        item's configured slots
        (`quota_setting.daily_time_range_quotas[].start_time` / `end_time`).
        `item_name` / `time_range_code` are server-derived and ignored on write.
        Send `[]` to clear. On read: `[{ api_code, scheduled_at, end_at, number,
        item_name, time_range_code }]`. |

        | `linked_form` | On write: string — the `entry_token` of an entry in
        the associated form, or `null` to clear. The server resolves the token
        against `associated_form_token`; an unknown token yields 422. On read:
        one of three shapes — (1) `null` if not linked; (2) `{ "deleted": true
        }` if the linked entry has been deleted; (3) Object `{ entry_token,
        serial_number, associated_fields, display_fields }` describing the
        linked entry, where `associated_fields` / `display_fields` map each
        `api_code` (from `associated_field_api_codes` /
        `display_field_api_codes` respectively) to that field's value, formatted
        per the linked field's own type (recursive — e.g. a `date` field renders
        as its naive wall-clock string, an `attachment` field renders as its
        array of file objects). |

        | `formula` | The computed result. A number, a naive date string
        (`YYYY-MM-DD`), or a string, depending on what the formula evaluates to.
        |

        | `page_break` | None — display-only field; never appears as an entry
        value. |

        | `description` | None — display-only field; never appears as an entry
        value. |

      properties:
        serial_number:
          type: integer
          description: Per-form auto-increment sequence number
          example: 42
        token:
          type: string
          description: Entry token
          example: aB2cD9eF
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      additionalProperties:
        description: >-
          Field value keyed by api_code; the value type depends on the field
          type.
    Pagination:
      type: object
      required:
        - total
        - next_cursor
      properties:
        total:
          type: integer
          description: Total number of records
          example: 123
        next_cursor:
          type: string
          nullable: true
          description: Opaque cursor for the next page; null when there are no more records
          example: NQ==
    ValidationErrorEnvelope:
      type: object
      required:
        - error
        - error_details
      description: >-
        Returned on model validation failures. error_details lists per-field
        errors.
      properties:
        error:
          type: string
          example: Name can't be blank
        error_details:
          type: array
          items:
            type: object
            required:
              - attribute
              - message
            properties:
              attribute:
                type: string
                example: name
              message:
                type: string
                example: can't be blank
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Error message
  securitySchemes:
    PersonalAccessToken:
      type: http
      scheme: bearer
      bearerFormat: PAT
      description: >
        Personal Access Token prefixed with `fh_`. Sent as `Authorization:
        Bearer fh_xxx`.

        The scope required by each endpoint is listed in that endpoint's
        description.

````