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

# Submit a form (public)

> Public submission endpoint.
Backend enforces required fields, disabled fields, and type-based validation.
For "select", "multi-select", and "multi-checkbox", values must be taken from form options[].value.
If a field has `relation`, submitted values must be related submission ids from the target form.
`one-to-one` and `many-to-one` accept a single id string.
`one-to-many` and `many-to-many` accept an array of id strings.
Requires the `x-tenant-id` header (`publicRoutes`) and a valid `x-service-status` header
(`enforceTenantStatus`, otherwise 400/423/403). `checkLimits("formSubmissions")` applies the
tenant's seat limit and rejects with 426 once the limit is reached. Status is always stored
as pending on this route; only `/forms/{id}/internal-submit` honours a body `status`.



## OpenAPI

````yaml /api-reference/ai-cms/openapi.json post /forms/{id}/submit
openapi: 3.1.0
info:
  title: Blog API
  version: 1.0.0
servers:
  - url: https://api.octaviatech.app/cms
    description: Production
security:
  - ApiKeyAuth: []
tags:
  - name: Tags
    description: Tag management endpoints
paths:
  /forms/{id}/submit:
    post:
      tags:
        - Form Submissions
      summary: Submit a form (public)
      description: >-
        Public submission endpoint.

        Backend enforces required fields, disabled fields, and type-based
        validation.

        For "select", "multi-select", and "multi-checkbox", values must be taken
        from form options[].value.

        If a field has `relation`, submitted values must be related submission
        ids from the target form.

        `one-to-one` and `many-to-one` accept a single id string.

        `one-to-many` and `many-to-many` accept an array of id strings.

        Requires the `x-tenant-id` header (`publicRoutes`) and a valid
        `x-service-status` header

        (`enforceTenantStatus`, otherwise 400/423/403).
        `checkLimits("formSubmissions")` applies the

        tenant's seat limit and rejects with 426 once the limit is reached.
        Status is always stored

        as pending on this route; only `/forms/{id}/internal-submit` honours a
        body `status`.
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            pattern: ^[a-fA-F0-9]{24}$
            example: '{{objectId}}'
          description: 24-char hex identifier of the target form.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - language
                - values
              properties:
                language:
                  type: string
                  description: >-
                    Language code for storing this submission (e.g., "en"). Not
                    validated against the form’s title keys by the service; use
                    a configured code.
                captchaToken:
                  type: string
                  description: >-
                    CAPTCHA token received on the client from provider widget.
                    Required only if the form has captcha.enabled=true.
                values:
                  type: object
                  description: |-
                    Key-value map where keys are form fields[].name.
                    Validation rules per field type:
                    - email: valid email
                    - tel: international phone pattern
                    - number: numeric value
                    - checkbox/switch: boolean
                    - multi-checkbox/multi-select: array
                    - select: one of options[].value
                  additionalProperties: {}
            examples:
              Submit:
                value:
                  language: en
                  values:
                    fullName: John Doe
                    email: john@example.com
                    message: Hello!
      responses:
        '200':
          description: Submitted
        '400':
          description: >-
            Bad request (missing or invalid x-tenant-id, or missing/invalid
            x-service-status)
        '403':
          description: >-
            Forbidden (form is not active, or the tenant status does not permit
            this method)
        '404':
          description: >-
            Form not found (unknown id, wrong tenant, or the form is not
            `formType: public`)
        '409':
          description: >-
            Conflict (a `one-to-one`/`one-to-many` relation uniqueness rule was
            violated)
        '423':
          description: Tenant is not active
        '426':
          description: Tenant form-submission limit exceeded
        '500':
          description: >-
            Server error, including field-validation failures (invalid id,
            missing required field, disabled field submitted, wrong type/format)
            — the service signals those with code 406, which is not a
            whitelisted response code and is normalized to 500
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````