> ## 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.

# Get a form

> **Required scope:** `form:read`.



## OpenAPI

````yaml /api-reference/openapi.yaml get /api/v1/forms/{token}
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/{token}:
    parameters:
      - name: token
        in: path
        description: Form token
        required: true
        schema:
          type: string
    get:
      tags:
        - Forms
      summary: Get a form
      description: '**Required scope:** `form:read`.'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/FormDetail'
        '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:
            - form:read
components:
  schemas:
    FormDetail:
      type: object
      required:
        - name
        - description
        - token
        - scene
        - layout
        - locale
        - timezone
        - created_at
        - updated_at
        - last_entry_created_at
        - entries_count
        - folder
        - fields
      properties:
        name:
          type: string
          example: Customer feedback
        description:
          type: string
          nullable: true
          example: Please share your feedback
        token:
          type: string
          example: Wabc12
        scene:
          type: string
          enum:
            - form
            - survey
            - exam
            - vote
            - registry
            - reservation
            - customer_acquisition
            - evaluation
            - online_payment
          example: survey
        layout:
          type: string
          description: Form layout
          enum:
            - classic
            - card
          example: classic
        locale:
          type: string
          description: Form locale, e.g. `en`, `zh-CN`, `it`.
          example: en
        timezone:
          type: string
          description: IANA timezone name used by the form when interpreting times.
          example: UTC
        created_at:
          type: string
          format: date-time
          example: '2026-05-12T08:00:00Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-05-12T09:00:00Z'
        last_entry_created_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Timestamp of the most recent entry submitted to this form; null when
            the form has no entries yet
          example: '2026-05-13T10:00:00Z'
        entries_count:
          type: integer
          example: 42
        folder:
          $ref: '#/components/schemas/FormFolderRef'
        fields:
          type: array
          description: >-
            Form fields. Each field's `type` determines which type-specific keys
            it carries — see the catalog of supported field types below.
          items:
            $ref: '#/components/schemas/FormField'
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Error message
    FormFolderRef:
      type: object
      nullable: true
      required:
        - token
        - name
      properties:
        token:
          type: string
          example: KaB2c1
        name:
          type: string
          example: Work
    FormField:
      description: >
        One field on a form, as returned in a form detail response. Every field
        returns the

        shared keys (label, api_code, notes, private, required, ...) plus its
        type-specific

        configuration determined by `type` — see the per-type sections below.
        The type-specific

        keys on read mirror what the same field type accepts on create / update,
        so a fetched

        form can be sent straight back through create / update without losing
        any setting.
      oneOf:
        - $ref: '#/components/schemas/FormFieldShortText'
        - $ref: '#/components/schemas/FormFieldLongText'
        - $ref: '#/components/schemas/FormFieldRadio'
        - $ref: '#/components/schemas/FormFieldCheckbox'
        - $ref: '#/components/schemas/FormFieldImageRadio'
        - $ref: '#/components/schemas/FormFieldImageCheckbox'
        - $ref: '#/components/schemas/FormFieldDropdown'
        - $ref: '#/components/schemas/FormFieldNumber'
        - $ref: '#/components/schemas/FormFieldEmail'
        - $ref: '#/components/schemas/FormFieldPhone'
        - $ref: '#/components/schemas/FormFieldDate'
        - $ref: '#/components/schemas/FormFieldName'
        - $ref: '#/components/schemas/FormFieldUrl'
        - $ref: '#/components/schemas/FormFieldAddress'
        - $ref: '#/components/schemas/FormFieldRating'
        - $ref: '#/components/schemas/FormFieldNps'
        - $ref: '#/components/schemas/FormFieldAttachment'
        - $ref: '#/components/schemas/FormFieldAudio'
        - $ref: '#/components/schemas/FormFieldCascade'
        - $ref: '#/components/schemas/FormFieldRanking'
        - $ref: '#/components/schemas/FormFieldMatrix'
        - $ref: '#/components/schemas/FormFieldLikert'
        - $ref: '#/components/schemas/FormFieldTime'
        - $ref: '#/components/schemas/FormFieldLocation'
        - $ref: '#/components/schemas/FormFieldSignature'
        - $ref: '#/components/schemas/FormFieldMatrixRating'
        - $ref: '#/components/schemas/FormFieldTable'
        - $ref: '#/components/schemas/FormFieldProduct'
        - $ref: '#/components/schemas/FormFieldBooking'
        - $ref: '#/components/schemas/FormFieldLinkedForm'
        - $ref: '#/components/schemas/FormFieldFormula'
        - $ref: '#/components/schemas/FormFieldPageBreak'
        - $ref: '#/components/schemas/FormFieldDescription'
      discriminator:
        propertyName: type
        mapping:
          short_text:
            $ref: '#/components/schemas/FormFieldShortText'
          long_text:
            $ref: '#/components/schemas/FormFieldLongText'
          radio:
            $ref: '#/components/schemas/FormFieldRadio'
          checkbox:
            $ref: '#/components/schemas/FormFieldCheckbox'
          image_radio:
            $ref: '#/components/schemas/FormFieldImageRadio'
          image_checkbox:
            $ref: '#/components/schemas/FormFieldImageCheckbox'
          dropdown:
            $ref: '#/components/schemas/FormFieldDropdown'
          number:
            $ref: '#/components/schemas/FormFieldNumber'
          email:
            $ref: '#/components/schemas/FormFieldEmail'
          phone:
            $ref: '#/components/schemas/FormFieldPhone'
          date:
            $ref: '#/components/schemas/FormFieldDate'
          name:
            $ref: '#/components/schemas/FormFieldName'
          url:
            $ref: '#/components/schemas/FormFieldUrl'
          address:
            $ref: '#/components/schemas/FormFieldAddress'
          rating:
            $ref: '#/components/schemas/FormFieldRating'
          nps:
            $ref: '#/components/schemas/FormFieldNps'
          attachment:
            $ref: '#/components/schemas/FormFieldAttachment'
          audio:
            $ref: '#/components/schemas/FormFieldAudio'
          cascade:
            $ref: '#/components/schemas/FormFieldCascade'
          ranking:
            $ref: '#/components/schemas/FormFieldRanking'
          matrix:
            $ref: '#/components/schemas/FormFieldMatrix'
          likert:
            $ref: '#/components/schemas/FormFieldLikert'
          time:
            $ref: '#/components/schemas/FormFieldTime'
          location:
            $ref: '#/components/schemas/FormFieldLocation'
          signature:
            $ref: '#/components/schemas/FormFieldSignature'
          matrix_rating:
            $ref: '#/components/schemas/FormFieldMatrixRating'
          table:
            $ref: '#/components/schemas/FormFieldTable'
          product:
            $ref: '#/components/schemas/FormFieldProduct'
          booking:
            $ref: '#/components/schemas/FormFieldBooking'
          linked_form:
            $ref: '#/components/schemas/FormFieldLinkedForm'
          formula:
            $ref: '#/components/schemas/FormFieldFormula'
          page_break:
            $ref: '#/components/schemas/FormFieldPageBreak'
          description:
            $ref: '#/components/schemas/FormFieldDescription'
    FormFieldShortText:
      title: Short Text
      description: '`short_text` field. Single-line text input.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - short_text
              example: short_text
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: string
                        minItems: 1
                        maxItems: 1
                      - type: string
                    description: Expected text. Single-element array or a bare string.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
    FormFieldLongText:
      title: Long Text
      description: '`long_text` field. Multi-line text input.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - long_text
              example: long_text
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: string
                        minItems: 1
                        maxItems: 1
                      - type: string
                    description: Expected text. Single-element array or a bare string.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
    FormFieldRadio:
      title: Radio
      description: '`radio` field. Single-select radio buttons.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - radio
              example: radio
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: integer
                      - type: integer
                    description: >-
                      Choice indices (0-based) into the field's `choices`. Array
                      (used for `checkbox` exam multi-select) or single integer.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldChoice'
    FormFieldCheckbox:
      title: Checkbox
      description: '`checkbox` field. Multi-select checkboxes.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - checkbox
              example: checkbox
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: integer
                      - type: integer
                    description: >-
                      Choice indices (0-based) into the field's `choices`. Array
                      (used for `checkbox` exam multi-select) or single integer.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldChoice'
    FormFieldImageRadio:
      title: Image Radio
      description: >-
        `image_radio` field. Single-select choices rendered as image cards. Each
        choice carries an image (see the choice schema).
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - image_radio
              example: image_radio
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldImageChoice'
    FormFieldImageCheckbox:
      title: Image Checkbox
      description: >-
        `image_checkbox` field. Multi-select choices rendered as image cards.
        Each choice carries an image (see the choice schema).
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - image_checkbox
              example: image_checkbox
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldImageChoice'
    FormFieldDropdown:
      title: Dropdown
      description: '`dropdown` field. Dropdown single-select.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - dropdown
              example: dropdown
            prompt:
              type: string
              nullable: true
              description: Placeholder shown before any choice is picked.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: integer
                      - type: integer
                    description: >-
                      Choice indices (0-based) into the field's `choices`. Array
                      (used for `checkbox` exam multi-select) or single integer.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldDropdownChoice'
    FormFieldNumber:
      title: Number
      description: '`number` field. Numeric input (integer or decimal).'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - number
              example: number
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
            precision:
              type: integer
              nullable: true
              description: Number of decimal places to enforce.
            display_as_percentage:
              type: boolean
              nullable: true
              description: Render the value with a trailing % sign in reports.
            range_min:
              type: number
              nullable: true
              description: Inclusive lower bound.
            range_max:
              type: number
              nullable: true
              description: Inclusive upper bound.
            icon_type:
              type: string
              enum:
                - none
                - number-2
                - dollar1
                - cny1
              description: Leading icon decoration.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: number
                        minItems: 1
                        maxItems: 1
                      - type: number
                    description: >-
                      Expected numeric value. Single-element array or a bare
                      number.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
    FormFieldEmail:
      title: Email
      description: '`email` field. Email address input.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - email
              example: email
            placeholder:
              type: string
              nullable: true
    FormFieldPhone:
      title: Phone
      description: '`phone` field. Mobile phone number input.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - phone
              example: phone
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
    FormFieldDate:
      title: Date
      description: >-
        `date` field. Date or date-time picker. The granularity is controlled by
        the field's `precision` setting (day, minute, etc.).
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - date
              example: date
            precision:
              type: string
              enum:
                - month
                - day
                - minute
                - second
              description: Picker granularity; controls the format of stored values.
            predefined_value:
              type: string
              nullable: true
              description: >-
                Default value. Naive string formatted per `precision`, or a
                dynamic token (`today`, `yesterday`, `tomorrow`, `before_N`,
                `after_N`).
            start_date:
              type: string
              nullable: true
              description: >-
                Inclusive earliest acceptable value. Naive string per
                `precision` or a dynamic token.
            end_date:
              type: string
              nullable: true
              description: >-
                Inclusive latest acceptable value. Naive string per `precision`
                or a dynamic token.
            as_age:
              type: boolean
              nullable: true
              description: Treat the value as an age (years) instead of a date.
    FormFieldName:
      title: Name
      description: >-
        `name` field. Person name. Inherits from `short_text`; the first/last
        name split is a UI concern and is not reflected in the stored value.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - name
              example: name
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: string
                        minItems: 1
                        maxItems: 1
                      - type: string
                    description: Expected text. Single-element array or a bare string.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
    FormFieldUrl:
      title: URL
      description: '`url` field. URL input.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - url
              example: url
            predefined_value:
              type: string
              nullable: true
              description: Default value pre-filled when the form opens.
            placeholder:
              type: string
              nullable: true
              description: Greyed hint text shown when empty.
    FormFieldAddress:
      title: Address
      description: '`address` field. Structured international postal address.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - address
              example: address
            predefined_value:
              type: object
              description: >-
                Default values pre-filled when the form opens, keyed by the
                address sections (`address_line1`, `address_line2`, `city`,
                `state`, `postal_code`, `country`).
              additionalProperties:
                type: string
    FormFieldRating:
      title: Rating
      description: >-
        `rating` field. Star / scale rating; `rating_max` sets the scale levels
        (1..N). This field type does not expose `choices` on V1.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - rating
              example: rating
            minimum_ratings_display_text:
              type: string
              nullable: true
              description: Caption shown next to the lowest rating.
            maximum_ratings_display_text:
              type: string
              nullable: true
              description: Caption shown next to the highest rating.
            rating_type:
              type: string
              enum:
                - star
                - heart
                - happy
              description: Visual style of the scale.
            rating_max:
              type: integer
              enum:
                - 3
                - 4
                - 5
                - 6
                - 7
                - 8
                - 9
                - 10
              description: Number of scale levels.
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: integer
                      - type: integer
                    description: >-
                      Choice indices (0-based) into the field's `choices`. Array
                      (used for `checkbox` exam multi-select) or single integer.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
    FormFieldNps:
      title: NPS
      description: >-
        `nps` field. Net Promoter Score 0..10 scale. This field type does not
        expose `choices` on V1.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - nps
              example: nps
            minimum_ratings_display_text:
              type: string
              nullable: true
              description: Caption shown next to the lowest rating.
            maximum_ratings_display_text:
              type: string
              nullable: true
              description: Caption shown next to the highest rating.
    FormFieldAttachment:
      title: Upload
      description: >-
        `attachment` field. File upload. On read, each entry value is an array
        of attachment descriptors with a signed download URL and file metadata.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - attachment
              example: attachment
            max_size:
              type: number
              enum:
                - 1
                - 5
                - 10
                - 20
                - 50
                - 100
                - 500
              description: Per-file max size in MB.
            max_file_quantity:
              type: integer
              nullable: true
              minimum: 1
              maximum: 15
              description: Maximum number of files.
    FormFieldAudio:
      title: Audio
      description: >-
        `audio` field. Voice recording. `max_duration` caps the recording length
        in minutes.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - audio
              example: audio
            max_duration:
              type: integer
              enum:
                - 1
                - 2
                - 5
                - 10
                - 30
              description: Maximum recording length in minutes (default 5).
    FormFieldCascade:
      title: Cascade
      description: >-
        `cascade` field. Cascading multi-level dropdown. The flattened `choices`
        array lists every selectable node; the parent/child hierarchy is part of
        the form designer state and not exposed here.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - cascade
              example: cascade
            levels:
              type: integer
              enum:
                - 2
                - 3
                - 4
              description: Number of cascade levels (default 2).
            prompt:
              type: string
              nullable: true
              description: >-
                Single prompt applied to every level (server fans this out to
                `prompts`).
            calculable:
              type: boolean
              nullable: true
              description: >-
                When true, this choice field can be referenced by a formula;
                every choice must then carry a numeric `operand_value`. The
                choice value summed for the selected option(s) is the field's
                formula value.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldCascadeChoiceInput'
    FormFieldRanking:
      title: Ranking
      description: '`ranking` field. Drag-to-rank ordering.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - ranking
              example: ranking
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldPlainChoice'
    FormFieldMatrix:
      title: Matrix Input
      description: >-
        `matrix` field. Matrix of statements × dimensions; each cell is itself a
        typed sub-field. The statement / dimension structure is part of the form
        designer state and not exposed in this response.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - matrix
              example: matrix
            statements:
              type: array
              items:
                $ref: '#/components/schemas/FormFieldStatementInput'
              description: Matrix rows.
            dimensions:
              type: array
              items:
                $ref: '#/components/schemas/FormFieldDimensionInput'
              description: Matrix columns; each is itself a typed sub-field.
    FormFieldLikert:
      title: Likert Scale
      description: >-
        `likert` field. Likert scale across multiple statements; `choices`
        enumerate the scale. The statement list is part of the form designer
        state and not exposed in this response.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - likert
              example: likert
            likert_choice_style:
              type: string
              enum:
                - single
                - multiple
              description: Whether each statement accepts one or many choices.
            statements:
              type: array
              items:
                $ref: '#/components/schemas/FormFieldStatementInput'
            answers:
              type: array
              description: >
                Scoring answers for this field. Only meaningful when the parent
                form's `scene`

                is `exam` or `evaluation` and the field type is one of the
                scorable types

                (`radio`, `checkbox`, `dropdown`, `short_text`, `long_text`,
                `number`, `likert`, `rating`).


                - `exam`: exactly one answer entry per field. For `checkbox` the
                `answer`
                  array may carry multiple choice indices; for the other choice / text /
                  number types it carries a single value. `likert` and `rating` are not
                  supported in `exam` scene.
                - `evaluation`: applies to choice-bearing fields, `likert`, and
                `rating`.
                  The `answers` array must contain one entry per scoreable position:
                  - choice-bearing (`radio` / `checkbox` / `dropdown`) and `likert`: one
                    entry per element of `choices`, positionally aligned (entry `i` scores
                    the `i`-th choice). On read the `answer` key is a single-element
                    array `[<0-based choice position>]`. On write the `answer` key is
                    ignored (positional alignment with `choices`).
                  - `rating`: one entry per rating level (size must equal `rating_max`,
                    default 5), positionally aligned with levels 1..rating_max. On read
                    the `answer` key is a single-element array `[<0-based position>]`
                    (level − 1). On write the `answer` key is ignored.
              items:
                type: object
                required:
                  - score
                properties:
                  answer:
                    oneOf:
                      - type: array
                        items:
                          type: integer
                      - type: integer
                    description: >-
                      Choice indices (0-based) into the field's `choices`. Array
                      (used for `checkbox` exam multi-select) or single integer.
                  score:
                    type: number
                    description: Points awarded when this answer matches.
            answer_explanation:
              type: string
              nullable: true
              description: >-
                Optional explanation shown to respondents after grading. Only
                honored in `exam` scene.
            choices:
              type: array
              description: >-
                Selectable options. On create / update: omit a previously-saved
                choice to delete it; provide its `api_code` to update it; omit
                `api_code` to add a new choice.
              items:
                $ref: '#/components/schemas/FormFieldOtherChoice'
    FormFieldTime:
      title: Time
      description: >-
        `time` field. Time of day. Whether seconds are captured is controlled by
        the field's `include_second` setting.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - time
              example: time
            include_second:
              type: boolean
              nullable: true
              description: Capture the seconds component of the time.
            predefined_value:
              type: object
              description: >-
                Default time, keyed by `hour`, `minute`, and optionally
                `second`. Each piece is an integer.
              properties:
                hour:
                  type: integer
                minute:
                  type: integer
                second:
                  type: integer
    FormFieldLocation:
      title: Location
      description: '`location` field. GPS location.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - location
              example: location
            localizable_on_mobile:
              type: boolean
              nullable: true
              description: Auto-locate the user via GPS on mobile.
    FormFieldSignature:
      title: Signature
      description: '`signature` field. Hand-drawn signature captured as an image attachment.'
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - signature
              example: signature
    FormFieldMatrixRating:
      title: Grid Rating
      description: >-
        `matrix_rating` field. Matrix of statements scored on a single rating
        scale. `statements` is required and must contain at least one row.
        `dimensions` is optional and, when supplied, must contain exactly one
        entry — implicitly a `rating` field, so its `type` discriminator is not
        surfaced on input or output. When `dimensions` is omitted: on create the
        server fills in a default rating dimension (`rating_max: 5`); on update
        the existing dimension is left untouched. When `dimensions` is supplied
        on update, preserve the existing dimension `api_code` (returned in the
        read shape) — replacing it deletes the dimension and creates a new one,
        which orphans any submitted entry values keyed under the old code.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - matrix_rating
              example: matrix_rating
            statements:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/FormFieldStatementInput'
              description: Matrix rows. At least one statement is required.
            dimensions:
              type: array
              minItems: 1
              maxItems: 1
              items:
                $ref: '#/components/schemas/FormFieldRatingDimensionInput'
              description: >-
                The rating-scale column. Optional — when present, must contain
                exactly one entry; each entry is treated as a `rating` field, so
                do not include a `type` discriminator. Omit on create to accept
                the default (`rating_max: 5`); omit on update to leave the
                existing dimension (and its `api_code`) untouched. If
                `rating_max` is omitted inside the supplied entry it defaults to
                5.
    FormFieldTable:
      title: Table
      description: >-
        `table` field. Repeatable table of typed sub-fields, one cell per
        dimension per row.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - table
              example: table
            init_row_length:
              type: integer
              minimum: 1
              maximum: 5
              description: Number of rows pre-rendered on the form (default 3).
            dimensions:
              type: array
              items:
                $ref: '#/components/schemas/FormFieldDimensionInput'
              description: Table columns; each is itself a typed sub-field.
    FormFieldProduct:
      title: Product
      description: >
        `product` field. Sellable items with optional specifications (SKUs).


        Per item: `name` (required); `price` / `original_price` for items
        without specifications; `inventory` for stock limits.


        Items with specifications declare `dimensions` (spec axes such as Size /
        Color) and a fully-enumerated `skus` list:

        - `dimensions[].api_code` and `dimensions[].options[].api_code` are
        required and must be supplied by the caller; they identify each axis and
        option stably.

        - `skus` must enumerate the **full Cartesian product** of all
        `dimensions` options — one SKU per combination, no missing or duplicate
        entries. Mismatches are rejected with 422.


        On read, items with no `dimensions` are returned without `dimensions` /
        `skus`; items with specs return both.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - product
              example: product
            goods_items:
              type: array
              items:
                $ref: '#/components/schemas/GoodsItemInput'
              description: Sellable items.
    FormFieldBooking:
      title: Booking
      description: >
        `booking` field. Time-slot reservation with per-item quota.


        Each `reservation_items[].quota_setting` specifies how slots are made
        available:

        - Provide `daily_time_range_quotas` with **all entries omitting**
        `start_time` / `end_time` for a weekly schedule — one quota entry per
        day in `available_days_of_week` (positional 1:1 mapping).

        - Provide `daily_time_range_quotas` with **all entries including** both
        `start_time` and `end_time` (and **omitting** `for_wday`) for recurring
        time slots that apply to every day in `available_days_of_week`.

        - Additionally set `for_wday` on **every** time-slot entry for a
        per-weekday schedule, where each slot applies only to its weekday;
        `available_days_of_week` is then derived from the weekdays used.


        Mixing shapes inside one `daily_time_range_quotas` is rejected with 422.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - booking
              example: booking
            item_allow_multiple_reservations:
              type: boolean
              description: Allow each respondent to book the same item multiple times.
            allow_multiple_items:
              type: boolean
              description: >-
                Allow each respondent to book multiple different items in one
                submission.
            allow_multiple_number:
              type: boolean
              description: Allow each respondent to specify quantities larger than 1.
            reservation_items:
              type: array
              items:
                $ref: '#/components/schemas/ReservationItemInput'
              description: Reservation items (slot categories) shown to respondents.
    FormFieldLinkedForm:
      title: Linked Form
      description: >
        `linked_form` field. Look up a row from another form by matching key
        fields.


        - `associated_form_token` must reference a form owned by the same
        billing account as the current API caller; cross-tenant lookups are
        rejected with 422.

        - `associated_field_api_codes` lists one or more **key fields** on the
        associated form used to match an entry. Each named field must either be
        a user-defined field whose type is in the allowed set (`short_text`,
        `long_text`, `email`, `phone`, `url`, `name`, `number`) or the system
        field `serial_number`. Other field types and other system api_codes are
        rejected with 422. At most 4 entries; duplicates are silently deduped.

        - `display_field_api_codes` lists fields whose value is shown after a
        match. Each must either be a user-defined field on the associated form
        (any type) or one of the system api_codes: `serial_number`,
        `created_at`, `updated_at`, `creator_name`. Other system / metainfo
        api_codes are rejected with 422. At most 20 entries; duplicates are
        silently deduped.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - linked_form
              example: linked_form
            associated_form_token:
              type: string
              description: >-
                Token of the form to look up (must be owned by the same billing
                account).
            associated_field_api_codes:
              type: array
              items:
                type: string
              description: >-
                api_codes of key fields on the associated form used to match an
                entry.
            display_field_api_codes:
              type: array
              items:
                type: string
              description: >-
                api_codes of fields on the associated form to display after a
                match.
    FormFieldFormula:
      title: Formula
      description: >-
        `formula` field. Computed field. Its value is derived from a formula
        referencing other fields; respondents do not fill it in.
      allOf:
        - $ref: '#/components/schemas/FormFieldBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - formula
              example: formula
            formula:
              type: string
              description: >
                The expression to compute. Reference another field with
                `$(ref)`, where `ref` is the

                target field's `cid` (for a field created in the same request)
                or its `api_code`.

                Reference a table column / matrix dimension with
                `$(parentRef.childRef)`, and a field

                on a linked form with `$(linkedRef_associated_targetApiCode)`.

                A formula placed inside a table (as a column) references a
                sibling column the same way —

                `$(thisTableRef.siblingRef)` — and can also reference top-level
                fields (`$(ref)`) and other

                tables' columns (`$(otherTableRef.childRef)`).

                **Aggregation:** referencing a table column from outside that
                column's row scope — a top-level

                formula referencing any table column, or an in-table formula
                referencing a *different* table's

                column — yields a list of values and must be wrapped in an
                aggregate function: `SUM`, `AVG`,

                `MIN`, or `MAX` for numeric columns, and `MIN` or `MAX` for date
                columns (string columns cannot

                be aggregated). A same-table sibling reference and a
                top-level-field reference are scalar and

                used directly. A non-aggregated cross-scope reference evaluates
                to null. Example:

                `SUM($(items.amount)) * 1.1`.

                Operators: `+ - * / ^` and comparisons `< <= > >= == !=`.

                Functions: `IF, ROUND, ROUNDUP, ROUNDDOWN, ABS, LOG, MAX, MIN,
                AVG, SUM, COUNT, DATE, DAYS, DATEADD, DATETIME_DIFF, ID`.

                `DATEADD(date, amount, unit)` and `DATETIME_DIFF(end, start,
                unit)` take a quoted, **case-sensitive** `unit`: `'y'` (year),
                `'M'` (month), `'w'` (week), `'d'` (day), `'h'` (hour), `'m'`
                (minute), `'s'` (second). Note `'M'` is month and `'m'` is
                minute. An unrecognized unit makes the formula evaluate to null.
                Example: `DATEADD($(start), 3, 'd')`.

                A referenced choice field must have a numeric `operand_value` on
                every choice and `calculable: true`.
            result_type:
              type: string
              nullable: true
              enum:
                - numeric
                - datetime
                - string
              description: Auto-inferred result type. Returned on read; ignored on write.
            precision:
              type: integer
              nullable: true
              description: Decimal places for a numeric result.
            display_as_percentage:
              type: boolean
              nullable: true
              description: Render a numeric result with a trailing % sign.
            thousands_separator:
              type: boolean
              nullable: true
              description: Render a numeric result with thousands separators.
            icon_type:
              type: string
              nullable: true
              enum:
                - none
                - formula-2
                - date-2
                - number-2
                - dollar1
                - cny1
                - sum
                - text2
              description: Leading icon decoration.
    FormFieldPageBreak:
      title: Page Break
      description: >-
        `page_break` field. Splits a `classic`-layout form into pages (renders
        previous/next buttons). Display-only — never submitted. On `card` layout
        it is stored but has NO effect (page breaks only paginate `classic`
        forms). Placement rules (enforced on form create/update): each page
        starts with a page_break, so use either 0 page_break fields (single-page
        form) or at least 2, and when any are present the FIRST field in
        `fields` must be a page_break.
      allOf:
        - $ref: '#/components/schemas/FormFieldDisplayBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - page_break
              example: page_break
            next_page_text:
              type: string
              nullable: true
              description: >-
                Label of the next-page button (max 20 chars). When omitted,
                defaults to a label in the form's `locale`.
            previous_page_text:
              type: string
              nullable: true
              description: >-
                Label of the previous-page button (max 20 chars). When omitted,
                defaults to a label in the form's `locale`.
            disable_previous_page:
              type: boolean
              description: Hide the previous-page button on this page.
            count_down:
              type: integer
              nullable: true
              description: >-
                Seconds the respondent must wait before the next-page button
                becomes clickable (0 = no wait).
    FormFieldDescription:
      title: Description
      description: >-
        `description` field. Display-only explanatory text (a section break).
        Uses `label` as an optional heading and `notes` as the descriptive body;
        takes no input.
      allOf:
        - $ref: '#/components/schemas/FormFieldDisplayBase'
        - type: object
          required:
            - type
          properties:
            type:
              type: string
              enum:
                - description
              example: description
    FormFieldBase:
      type: object
      description: Shared keys returned for every form field, regardless of type.
      required:
        - type
        - label
        - api_code
        - notes
        - private
        - required
        - customized_validation_message
      properties:
        type:
          type: string
          description: >-
            Field type identifier. Determines which type-specific keys are
            present on the field.
          enum:
            - short_text
            - long_text
            - radio
            - checkbox
            - image_radio
            - image_checkbox
            - dropdown
            - number
            - email
            - phone
            - date
            - name
            - url
            - address
            - rating
            - nps
            - attachment
            - audio
            - signature
            - cascade
            - ranking
            - matrix
            - matrix_rating
            - likert
            - time
            - location
            - product
            - table
            - booking
            - linked_form
            - formula
            - page_break
            - description
          example: short_text
        label:
          type: string
          example: Name
        api_code:
          type: string
          description: >
            Stable identifier of the field; used as the key for this field's
            value in entry payloads.


            **Always present on read.** On form create / update, `api_code` is
            optional in the request body:

            - **Omit** to add a new field — the server auto-generates an
            `api_code` (e.g. `field_3`).

            - **Provide an existing `api_code`** to target an existing field for
            update; fields whose `api_code` is absent from the request are
            dropped.


            The same rule applies to every other `api_code`-bearing sub-object
            on a field (e.g. choices, and statements/dimensions/levels of
            `matrix`, `likert`, `cascade`).
          example: field_1
        cid:
          type: string
          nullable: true
          description: >-
            Client-supplied stable identifier. Use it to reference a field from
            a formula in the same request before the server has assigned an
            `api_code` (see the `formula` field type). Echoed back on read; null
            when none was supplied. Charset `[A-Za-z0-9_-]`, length 6–12, unique
            within the form, and must not look like a server `api_code`.
        notes:
          type: string
          nullable: true
          example: Please use your real name
        private:
          type: boolean
          description: Whether the field is private
          example: false
        required:
          type: boolean
          example: true
        customized_validation_message:
          type: string
          nullable: true
          description: >-
            Override the default validation error message (max 50 chars). Null
            when not set.
    FormFieldChoice:
      type: object
      description: >-
        A selectable option on `radio` and `checkbox` fields — the choice types
        that support both an `other` fallback and an extended text input. Every
        key emitted on read is also accepted on write, so a fetched choice can
        be sent back unchanged on update.
      required:
        - label
        - api_code
        - is_other
        - selected
        - allow_extended_text
        - extended_text_required
        - extended_text_placeholder
      properties:
        label:
          type: string
          description: Display label of the choice.
          example: Option A
        api_code:
          type: string
          description: >-
            Stable identifier of the choice. Always present on read. On form
            create / update, omit to add a new choice (the server auto-generates
            the value), pass an existing value to target an existing choice for
            update, and omit an existing choice entirely to delete it.
          example: choice_abc
        is_other:
          type: boolean
          description: >-
            True when this is the "other / please specify" free-text fallback
            option. At most one choice per field can be marked. The "other"
            choice carries its own free-text input via the entry value's
            `other_text` key, and the extended-text triplet has no effect on it
            — those keys are silently ignored on write for an `is_other` choice.
          example: false
        selected:
          type: boolean
          nullable: true
          description: Whether this choice is pre-selected by default. Null when never set.
        allow_extended_text:
          type: boolean
          description: >-
            Whether respondents may type free text alongside this choice. Has no
            effect on an `is_other` choice.
        extended_text_required:
          type: boolean
          description: >-
            Whether the extended text is required when this choice is picked.
            Has no effect on an `is_other` choice.
        extended_text_placeholder:
          type: string
          nullable: true
          description: >-
            Placeholder text for the extended text input. Has no effect on an
            `is_other` choice.
        operand_value:
          type: number
          nullable: true
          description: >-
            Numeric weight summed when this choice is selected; required on
            every choice when the field is `calculable`.
    FormFieldImageChoice:
      type: object
      description: >-
        A selectable option on `image_radio` and `image_checkbox` fields. Image
        choices do not support an `other` fallback or extended text.
      required:
        - label
        - api_code
        - selected
        - image
      properties:
        label:
          type: string
          description: Display label of the choice.
          example: Option A
        api_code:
          type: string
          description: >-
            Stable identifier of the choice. Always present on read. On form
            create / update, omit to add a new choice (the server auto-generates
            the value), pass an existing value to target an existing choice for
            update, and omit an existing choice entirely to delete it.
          example: choice_abc
        selected:
          type: boolean
          nullable: true
          description: Whether this choice is pre-selected by default. Null when never set.
        operand_value:
          type: number
          nullable: true
          description: >-
            Numeric weight summed when this choice is selected; required on
            every choice when the field is `calculable`.
        image:
          nullable: true
          description: >-
            The image shown on this choice card; null when the choice has no
            image.
          allOf:
            - $ref: '#/components/schemas/FieldImage'
    FormFieldDropdownChoice:
      type: object
      description: >-
        A selectable option on a `dropdown` field — supports an `other` fallback
        and a calculation `operand_value`.
      required:
        - label
        - api_code
        - is_other
        - selected
      properties:
        label:
          type: string
          description: Display label of the choice.
          example: Option A
        api_code:
          type: string
          description: >-
            Stable identifier of the choice. Always present on read; omit to
            add, provide to update, omit-to-delete on write.
          example: choice_abc
        is_other:
          type: boolean
          description: >-
            True when this is the "other / please specify" fallback. At most one
            per field.
          example: false
        selected:
          type: boolean
          nullable: true
          description: Whether this choice is pre-selected by default. Null when never set.
        operand_value:
          type: number
          nullable: true
          description: >-
            Numeric weight summed when this choice is selected; required on
            every choice when the field is `calculable`.
    FormFieldCascadeChoiceInput:
      type: object
      required:
        - label
      description: >-
        A cascade-tree node. `sub_choices` recursively nests the same shape down
        to `levels` deep.
      properties:
        label:
          type: string
          description: Display label of the cascade node.
        api_code:
          type: string
        operand_value:
          type: number
          nullable: true
          description: >-
            Numeric weight summed when this choice is selected; required on
            every choice when the field is `calculable`.
        sub_choices:
          type: array
          items:
            $ref: '#/components/schemas/FormFieldCascadeChoiceInput'
    FormFieldPlainChoice:
      type: object
      description: >-
        A selectable option on a `ranking` field. Does not support an `other`
        fallback or an extended text input.
      required:
        - label
        - api_code
        - selected
      properties:
        label:
          type: string
          description: Display label of the choice.
          example: Option A
        api_code:
          type: string
          description: >-
            Stable identifier of the choice. Always present on read. On form
            create / update, omit to add a new choice (the server auto-generates
            the value), pass an existing value to target an existing choice for
            update, and omit an existing choice entirely to delete it.
          example: choice_abc
        selected:
          type: boolean
          nullable: true
          description: Whether this choice is pre-selected by default. Null when never set.
    FormFieldStatementInput:
      type: object
      description: A row/statement on a `matrix` or `likert` field.
      properties:
        label:
          type: string
        api_code:
          type: string
    FormFieldDimensionInput:
      type: object
      description: >
        A matrix column. Each dimension is itself a typed sub-field; pass the
        same keys as a top-level

        field of that type (e.g. `type: short_text` accepts `placeholder`,
        `type: number` accepts

        `range_min` / `range_max`). The supported dimension types are restricted
        to text-like and

        numeric-like fields. Column order follows the array index in the
        request.
      required:
        - type
        - label
      properties:
        type:
          type: string
          enum:
            - short_text
            - long_text
            - checkbox
            - dropdown
            - cascade
            - phone
            - email
            - number
            - date
            - time
            - attachment
            - formula
          description: Field type of the dimension cell.
        label:
          type: string
        api_code:
          type: string
          pattern: ^field_\d+$
          description: >-
            Stable identifier of the dimension. Omit to add a new dimension;
            provide an existing api_code to update the matching dimension on the
            parent field (the accompanying `type` must match the stored one).
      additionalProperties: true
    FormFieldOtherChoice:
      type: object
      description: >-
        A selectable option on `likert` fields — supports an `other` fallback,
        but no extended text input.
      required:
        - label
        - api_code
        - is_other
        - selected
      properties:
        label:
          type: string
          description: Display label of the choice.
          example: Option A
        api_code:
          type: string
          description: >-
            Stable identifier of the choice. Always present on read. On form
            create / update, omit to add a new choice (the server auto-generates
            the value), pass an existing value to target an existing choice for
            update, and omit an existing choice entirely to delete it.
          example: choice_abc
        is_other:
          type: boolean
          description: >-
            True when this is the "other / please specify" free-text fallback
            option. At most one per field.
          example: false
        selected:
          type: boolean
          nullable: true
          description: Whether this choice is pre-selected by default. Null when never set.
    FormFieldRatingDimensionInput:
      type: object
      description: >-
        The single rating column of a `matrix_rating` field. Same keys as a
        top-level `rating` field, except `label` — the server hard-codes the
        rating dimension's label and ignores any value supplied here. On update,
        preserve the existing `api_code` (returned in the read shape) — omitting
        it deletes the dimension and creates a new one, which orphans any
        submitted entry values keyed under the old code.
      properties:
        api_code:
          type: string
          pattern: ^field_\d+$
          description: >-
            Stable identifier of the rating dimension. Omit to add it; provide
            the existing api_code (returned in the read shape) to update it in
            place — replacing it deletes the dimension and orphans any submitted
            entry values keyed under the old code.
        rating_type:
          type: string
          enum:
            - star
            - heart
            - happy
        rating_max:
          type: integer
          enum:
            - 3
            - 4
            - 5
            - 6
            - 7
            - 8
            - 9
            - 10
        minimum_ratings_display_text:
          type: string
          nullable: true
        maximum_ratings_display_text:
          type: string
          nullable: true
    GoodsItemInput:
      type: object
      description: A sellable item on a `product` field.
      required:
        - name
      properties:
        api_code:
          type: string
          description: Identifier of an existing item; omit to create a new one.
        name:
          type: string
        price:
          type: number
          description: Price for items without `dimensions`. Defaults to 0.
        original_price:
          type: number
          nullable: true
        inventory:
          type: integer
          minimum: 0
          nullable: true
          description: >-
            Available stock when the item has no `dimensions`. Omit or null for
            unlimited.
        min_purchase_quantity:
          type: integer
          minimum: 0
          nullable: true
        max_purchase_quantity:
          type: integer
          minimum: 0
          nullable: true
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/GoodsDimensionInput'
          description: >-
            Specification axes (Size / Color / ...). Omit for a simple priced
            item.
        skus:
          type: array
          items:
            $ref: '#/components/schemas/GoodsSkuInput'
          description: >-
            Per-combination overrides. Required when `dimensions` is present;
            must enumerate the full Cartesian product (one SKU per combination).
        images:
          type: array
          maxItems: 5
          items:
            $ref: '#/components/schemas/FieldImageInput'
          description: >-
            Item images shown to respondents, in display order (1–5). Only image
            products carry images: the key is returned and accepted only for
            image items, and supplying it for a non-image item is rejected. Omit
            to keep existing images; a non-empty array replaces the list. An
            image item must always keep at least one image (it cannot be cleared
            to empty).
    ReservationItemInput:
      type: object
      description: A reservable item (e.g. a service / room).
      required:
        - name
      properties:
        api_code:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        selected:
          type: boolean
          description: Pre-select this item by default.
        start_date:
          type: string
          nullable: true
          format: date-time
          description: Earliest reservable date (ISO 8601).
        end_date:
          type: string
          nullable: true
          format: date-time
          description: Latest reservable date (ISO 8601).
        quota_setting:
          description: >-
            Quota configuration for this item. On create, omit to default to
            Monday–Saturday reservable with no quota cap. On update, omit to
            keep the existing setting; pass a value to replace it.
          allOf:
            - $ref: '#/components/schemas/ReservationQuotaSettingInput'
        images:
          type: array
          maxItems: 5
          items:
            $ref: '#/components/schemas/FieldImageInput'
          description: >-
            Item images shown to respondents, in display order (at most 5). Omit
            to keep existing images; pass an empty array to clear them; a
            non-empty array replaces the list.
    FormFieldDisplayBase:
      type: object
      description: >-
        Shared read keys for display-only fields (page_break, description). Same
        shape as the common field read keys, except `label` may be null/empty.
      required:
        - type
        - label
        - api_code
        - notes
        - private
        - required
        - customized_validation_message
      properties:
        type:
          type: string
          enum:
            - short_text
            - long_text
            - radio
            - checkbox
            - image_radio
            - image_checkbox
            - dropdown
            - number
            - email
            - phone
            - date
            - name
            - url
            - address
            - rating
            - nps
            - attachment
            - audio
            - signature
            - cascade
            - ranking
            - matrix
            - matrix_rating
            - likert
            - time
            - location
            - product
            - table
            - booking
            - linked_form
            - formula
            - page_break
            - description
          example: page_break
        label:
          type: string
          nullable: true
          example: ''
        api_code:
          type: string
          example: field_1
        notes:
          type: string
          nullable: true
        private:
          type: boolean
          example: false
        required:
          type: boolean
          example: false
        customized_validation_message:
          type: string
          nullable: true
    FieldImage:
      type: object
      description: An image attached to a field element, as returned by GET.
      required:
        - id
        - url
      properties:
        id:
          type: string
          description: Image attachment id. Reference it back via `{ id }` on update.
        url:
          type: string
          nullable: true
          description: Public URL of the image.
    GoodsDimensionInput:
      type: object
      description: One specification axis of a goods item (e.g. Size, Color).
      required:
        - api_code
        - label
        - options
      properties:
        api_code:
          type: string
          description: >-
            Stable identifier of the dimension. Required; supplied by the
            caller.
        label:
          type: string
        options:
          type: array
          items:
            $ref: '#/components/schemas/GoodsDimensionOptionInput'
    GoodsSkuInput:
      type: object
      description: >
        One SKU (specific combination of dimension options) of a goods item with
        multi-spec items.

        The `specification` map keys are `dimensions[].api_code` and values are
        the corresponding

        `dimensions[].options[].api_code`. The set of SKUs must enumerate the
        Cartesian product

        of all dimension options exactly once.
      required:
        - specification
      properties:
        specification:
          type: object
          description: Map of dimension api_code → option api_code.
          additionalProperties:
            type: string
        price:
          type: number
        original_price:
          type: number
          nullable: true
        inventory:
          type: integer
          minimum: 0
          nullable: true
          description: Available stock for this SKU. Omit or null for unlimited.
    FieldImageInput:
      type: object
      additionalProperties: false
      description: >-
        Reference to an image used inside a field definition. Provide exactly
        one of `id` (reuse an image already attached to this form) or
        `upload_id` (a 2-step upload prepared via POST /api/v1/attachments with
        the matching purpose: `choice_image` for image choices, `product_image`
        for product items, `booking_image` for booking items). A `url` key from
        a previous read is accepted and ignored, so fetched payloads can be sent
        back verbatim.
      oneOf:
        - required:
            - id
        - required:
            - upload_id
      properties:
        id:
          type: string
          minLength: 1
          description: >-
            Existing image attachment id to reuse — must be an image of the
            matching kind that is either not yet attached to a form or already
            attached to this form.
        upload_id:
          type: string
          minLength: 1
          description: >-
            upload_id from POST /api/v1/attachments, after the file was PUT to
            its upload_url.
        url:
          type: string
          description: Read-only; the image URL echoed by GET. Ignored on write.
    ReservationQuotaSettingInput:
      type: object
      description: >-
        Quota configuration for a `reservation_items[]`. See
        `daily_time_range_quotas[]` for the two supported modes.
      required:
        - daily_time_range_quotas
      properties:
        available_days_of_week:
          type: array
          description: >
            Days of the week the item is reservable. Required for the
            weekly-schedule and recurring-time-slot

            shapes (entries without `for_wday`). Ignored for the per-weekday
            shape (every entry carries `for_wday`),

            where the reservable days are derived from those weekdays.
          items:
            type: string
            enum:
              - monday
              - tuesday
              - wednesday
              - thursday
              - friday
              - saturday
              - sunday
        daily_time_range_quotas:
          type: array
          items:
            $ref: '#/components/schemas/DailyTimeRangeQuotaInput'
    GoodsDimensionOptionInput:
      type: object
      description: >-
        One option of a goods specification dimension. The caller assigns and
        owns `api_code`.
      required:
        - api_code
        - label
      properties:
        api_code:
          type: string
          description: Stable identifier of the option. Required; supplied by the caller.
        label:
          type: string
    DailyTimeRangeQuotaInput:
      type: object
      description: >
        One quota entry inside a `reservation_items[].quota_setting`.

        All entries inside a single `daily_time_range_quotas` must agree on
        their shape:


        - All entries **omit** `start_time` / `end_time` → weekly schedule; one
        entry per element
          of `available_days_of_week` in the same order, each providing `quota` for that day.
        - All entries **include** `start_time` / `end_time` (`HH:MM` strings)
        and **omit** `for_wday`
          → the same recurring time slots apply to every day in `available_days_of_week`.
        - All entries **include** `start_time` / `end_time` and `for_wday` →
        per-weekday time slots;
          each entry's slot applies only to its `for_wday`. `available_days_of_week` is then derived
          from the weekdays present and any supplied value is ignored.

        Mixing shapes is rejected with 422.
      properties:
        quota:
          type: integer
          minimum: 0
          nullable: true
          description: >-
            Total bookable slots in this window; null or omitted means
            unlimited.
        for_wday:
          type: string
          enum:
            - monday
            - tuesday
            - wednesday
            - thursday
            - friday
            - saturday
            - sunday
          description: >-
            Weekday this slot applies to. Provide it on every time-slot entry
            for a per-weekday schedule, or omit it on every entry for an
            all-days schedule.
        start_time:
          type: string
          pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$
          description: Slot start time, formatted `HH:MM` (24-hour).
        end_time:
          type: string
          pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$
          description: Slot end time, formatted `HH:MM` (24-hour).
  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.

````