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

# Create a form

> Creates a form and returns it with its endpoint URL.

Send `name` (required) and any of the configuration blocks. Excluded configuration blocks return defaults in the response. If you try to configure something your plan does not include, the request is refused and no form gets created.



## OpenAPI

````yaml https://api.formcarry.com/docs-json post /v1/forms
openapi: 3.0.0
info:
  title: formcarry API
  description: >-
    Welcome to the formcarry API.


    Authenticate every request with an API key from your team's API page in the
    dashboard, sent as `Authorization: Bearer fc_live_...`.

    Requests and responses are JSON.


    Lists are paginated with a cursor: pass a response's `next_cursor` as
    `cursor` to get the next page, until `next_cursor` is null.


    Errors return a `code` you can act on and a `message` you can show. Every
    response includes an `X-Request-Id` header; quote it when you contact
    support.
  version: '1'
  contact: {}
servers:
  - url: https://api.formcarry.com
security: []
tags:
  - name: forms
    description: Your forms
  - name: submissions
    description: Submissions received by a form
  - name: me
    description: The key you are using
  - name: health
    description: Service status
paths:
  /v1/forms:
    post:
      tags:
        - forms
      summary: Create a form
      description: >-
        Creates a form and returns it with its endpoint URL.


        Send `name` (required) and any of the configuration blocks. Excluded
        configuration blocks return defaults in the response. If you try to
        configure something your plan does not include, the request is refused
        and no form gets created.
      operationId: FormsController_create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateFormBody'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FormResource'
        '400':
          description: >-
            The body has a field that is missing, unknown or has the wrong
            value. `param` names it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                invalid_parameter:
                  summary: invalid_parameter
                  value:
                    error:
                      type: invalid_request_error
                      code: invalid_parameter
                      message: No email server with that id belongs to your team.
                      param: self_email_notification.sender.server_id
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
        '401':
          description: The request carried no usable key or token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                missing_bearer:
                  summary: missing_bearer
                  value:
                    error:
                      type: authentication_error
                      code: missing_bearer
                      message: >-
                        Send your key as "Authorization: Bearer fc_live_..." on
                        every request.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                invalid_key:
                  summary: invalid_key
                  value:
                    error:
                      type: authentication_error
                      code: invalid_key
                      message: >-
                        This API key or access token is unknown, revoked or
                        expired.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                wrong_audience:
                  summary: wrong_audience
                  value:
                    error:
                      type: authentication_error
                      code: wrong_audience
                      message: >-
                        This access token was issued for a different resource.
                        Authorize again for this server.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
        '403':
          description: The key is valid but may not create this form.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                insufficient_scope:
                  summary: insufficient_scope
                  value:
                    error:
                      type: permission_error
                      code: insufficient_scope
                      message: This key is missing the forms:write scope.
                      required:
                        - forms:write
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                form_access_restricted:
                  summary: form_access_restricted
                  value:
                    error:
                      type: permission_error
                      code: form_access_restricted
                      message: >-
                        This key is restricted to specific forms and cannot
                        create new ones.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                owner_unverified:
                  summary: owner_unverified
                  value:
                    error:
                      type: permission_error
                      code: owner_unverified
                      message: >-
                        The team owner must verify their email address before
                        the API can be used.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                plan_restricted:
                  summary: plan_restricted
                  value:
                    error:
                      type: permission_error
                      code: plan_restricted
                      message: >-
                        You have reached your form limit, please upgrade to
                        create a new form
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                team_inactive:
                  summary: team_inactive
                  value:
                    error:
                      type: permission_error
                      code: team_inactive
                      message: The team that owns this key is not active.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
        '429':
          description: Slow down and retry after the Retry-After header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
              examples:
                rate_limited:
                  summary: rate_limited
                  value:
                    error:
                      type: rate_limit_error
                      code: rate_limited
                      message: Too many requests.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
                scan_concurrency:
                  summary: scan_concurrency
                  value:
                    error:
                      type: rate_limit_error
                      code: scan_concurrency
                      message: >-
                        At most 2 filtered submission requests may run at once
                        per key. Wait for the running ones to finish.
                      request_id: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
      security:
        - api_key: []
components:
  schemas:
    CreateFormBody:
      type: object
      properties:
        active:
          type: boolean
          description: Inactive forms reject submissions.
        folder_id:
          type: string
          nullable: true
          description: The folder the form is filed in. null for no folder.
        storage:
          $ref: '#/components/schemas/StorageBlock'
        spam:
          $ref: '#/components/schemas/SpamBlock'
        self_email_notification:
          description: The email you get on every submission.
          allOf:
            - $ref: '#/components/schemas/SelfEmailNotificationBlock'
        auto_response:
          description: The email the person who submitted receives.
          allOf:
            - $ref: '#/components/schemas/AutoResponseBlock'
        after_submit:
          description: What the visitor sees after submitting.
          allOf:
            - $ref: '#/components/schemas/AfterSubmitBlock'
        validation:
          description: Rules a submission must pass.
          allOf:
            - $ref: '#/components/schemas/ValidationBlock'
        team_id:
          type: string
          description: >-
            Team that owns the new form. Required when the credential covers
            several teams (OAuth connections).
          example: 64b000000000000000000001
        name:
          type: string
          maxLength: 128
          example: Contact form
      required:
        - name
    FormResource:
      type: object
      properties:
        id:
          type: string
          example: AbC123xyz
          readOnly: true
        team_id:
          type: string
          readOnly: true
        name:
          type: string
          example: Contact form
        endpoint:
          type: string
          example: https://formcarry.com/s/AbC123xyz
          readOnly: true
          description: Where your HTML form posts.
        active:
          type: boolean
          description: Inactive forms reject submissions.
        avatar:
          type: string
          example: 🚀
          readOnly: true
        folder_id:
          type: string
          nullable: true
          description: The folder the form is filed in, or null for none.
        created_at:
          type: string
          example: '2026-01-15T10:00:00.000Z'
          readOnly: true
        last_submission_at:
          type: string
          nullable: true
          readOnly: true
          description: When the newest submission arrived, or null before the first.
        submissions:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/SubmissionCounts'
        storage:
          $ref: '#/components/schemas/StorageBlock'
        spam:
          $ref: '#/components/schemas/SpamBlock'
        self_email_notification:
          $ref: '#/components/schemas/SelfEmailNotificationBlock'
        auto_response:
          $ref: '#/components/schemas/AutoResponseBlock'
        after_submit:
          $ref: '#/components/schemas/AfterSubmitBlock'
        webhooks:
          readOnly: true
          description: Managed at /v1/forms/{form_id}/webhooks; one per form for now.
          type: array
          items:
            $ref: '#/components/schemas/WebhookResource'
        validation:
          $ref: '#/components/schemas/ValidationBlock'
      required:
        - id
        - team_id
        - name
        - endpoint
        - active
        - avatar
        - folder_id
        - created_at
        - last_submission_at
        - submissions
        - storage
        - spam
        - self_email_notification
        - auto_response
        - after_submit
        - webhooks
        - validation
    ErrorEnvelope:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
      required:
        - error
    StorageBlock:
      type: object
      properties:
        store_submissions:
          type: boolean
          description: >-
            When false, submissions are forwarded by email and webhook but
            nothing is stored.
        keep_for:
          type: string
          enum:
            - 30_days
            - 60_days
            - 90_days
            - 180_days
            - 365_days
            - forever
          description: How long stored submissions are kept before they are removed.
    SpamBlock:
      type: object
      properties:
        protection:
          type: boolean
          description: formcarry's built-in spam filter.
        captcha:
          $ref: '#/components/schemas/CaptchaBlock'
    SelfEmailNotificationBlock:
      type: object
      properties:
        enabled:
          type: boolean
          description: Send an email to the recipients on every submission.
        recipients:
          description: >-
            Who receives the email. Replaces the whole list. The free plan
            allows one address.
          example:
            - me@company.com
          type: array
          items:
            type: string
        include_spam:
          type: boolean
          description: Also send the email for submissions the spam filter flagged.
        subject:
          type: string
          nullable: true
          maxLength: 256
          description: Email subject. null uses formcarry's default.
        logo_url:
          type: string
          nullable: true
          maxLength: 2048
          description: >-
            The logo of the email, shown by the built-in themes and available to
            a custom template. Upload one with the images endpoint (use
            `self_email_notification_logo`) or use any public PNG, JPEG or GIF
            URL.
          example: https://example.com/logo.png
        logo_height:
          type: number
          nullable: true
          minimum: 16
          maximum: 400
          description: Logo height in pixels. null lets the template decide.
        template:
          $ref: '#/components/schemas/SelfEmailNotificationTemplateBlock'
        sender:
          $ref: '#/components/schemas/SenderBlock'
    AutoResponseBlock:
      type: object
      properties:
        enabled:
          type: boolean
          description: >-
            Send a reply to the person who submitted the form (their email field
            is used as the address).
        subject:
          type: string
          nullable: true
          maxLength: 256
          description: Subject of the reply.
        from_name:
          type: string
          nullable: true
          maxLength: 128
          description: The name the reply appears to come from.
        logo_url:
          type: string
          nullable: true
          maxLength: 2048
          description: >-
            The logo of the reply, shown by the built-in themes and available to
            a custom template. Upload one with the images endpoint (use
            `auto_response_logo`) or use any public PNG, JPEG or GIF URL.
          example: https://example.com/logo.png
        logo_height:
          type: number
          nullable: true
          minimum: 16
          maximum: 400
          description: Logo height in pixels. null lets the template decide.
        template:
          $ref: '#/components/schemas/AutoResponseTemplateBlock'
    AfterSubmitBlock:
      type: object
      properties:
        type:
          type: string
          enum:
            - formcarry_page
            - redirect
          description: >-
            formcarry_page: show formcarry's thank you page. redirect: send the
            visitor to your own URL.
        page:
          $ref: '#/components/schemas/AfterSubmitPageBlock'
        redirect:
          $ref: '#/components/schemas/AfterSubmitRedirectBlock'
    ValidationBlock:
      type: object
      properties:
        enabled:
          type: boolean
          description: Reject submissions that fail the rules.
        rules:
          description: Replaces the whole list.
          type: array
          items:
            $ref: '#/components/schemas/ValidationRule'
    SubmissionCounts:
      type: object
      properties:
        this_month:
          type: number
          description: Submissions received this calendar month.
        all_time:
          type: number
          nullable: true
          description: Submissions received since the form was created.
      required:
        - this_month
        - all_time
    WebhookResource:
      type: object
      properties:
        id:
          type: string
          example: whk_3f9Kq2bLm8xZpQ1rT7vWc0
          readOnly: true
        url:
          type: string
          example: https://example.com/hooks/formcarry
        enabled:
          type: boolean
        description:
          type: string
          nullable: true
          example: CRM sync
        events:
          example:
            - submission.created
          type: array
          items:
            type: string
        signing:
          description: >-
            How deliveries are signed: an HMAC-SHA256 of "<timestamp>.<raw
            body>" with the secret, sent as "t=<unix seconds>,v1=<hex>" in this
            header. Recompute it over the raw body you received, compare in
            constant time, and refuse a timestamp older than a few minutes.
            Retries are signed again with a fresh timestamp.
          allOf:
            - $ref: '#/components/schemas/WebhookSigning'
        last_delivery:
          nullable: true
          readOnly: true
          description: >-
            Always null: the delivery log is the record, at GET
            .../webhooks/{webhook_id}/deliveries.
          allOf:
            - $ref: '#/components/schemas/WebhookLastDelivery'
        created_at:
          type: string
          example: '2026-09-13T12:00:00.000Z'
          readOnly: true
      required:
        - id
        - url
        - enabled
        - description
        - events
        - signing
        - last_delivery
        - created_at
    ErrorBody:
      type: object
      properties:
        type:
          type: string
          enum:
            - authentication_error
            - permission_error
            - invalid_request_error
            - rate_limit_error
            - api_error
          example: invalid_request_error
        code:
          type: string
          example: invalid_parameter
        message:
          type: string
          example: limit must not be greater than 100
        param:
          type: string
          description: The offending parameter, when there is one
          example: limit
        required:
          description: >-
            On insufficient_scope: the scopes the request needs. Reissue the key
            with them.
          example:
            - submissions:write
          type: array
          items:
            type: string
        retry_after:
          type: number
          description: 'On scan_concurrency: seconds to wait before trying again.'
          example: 2
        request_id:
          type: string
          description: Echoes X-Request-Id. Quote it when contacting support.
          example: 2f9c1a7e-5b31-4d2e-9c0a-8e7f6d5c4b3a
      required:
        - type
        - code
        - message
        - request_id
    CaptchaBlock:
      type: object
      properties:
        provider:
          type: string
          enum:
            - none
            - recaptcha
            - hcaptcha
            - turnstile
          description: >-
            Which captcha your form embeds. formcarry verifies the response with
            this secret key.
        secret_key:
          type: string
          nullable: true
          maxLength: 512
          description: >-
            The secret key from your captcha provider's dashboard. Write only: a
            read carries secret_key_set instead, and null on a write keeps the
            stored one. To drop it, set the provider to none.
          writeOnly: true
        secret_key_set:
          type: boolean
          readOnly: true
          description: >-
            Whether a secret key is stored. Read only: ignored on a write, so a
            form read and sent back whole is fine.
    SelfEmailNotificationTemplateBlock:
      type: object
      properties:
        type:
          type: string
          enum:
            - formcarry
            - custom
          description: >-
            formcarry: one of the built-in themes. custom: your own template,
            sent in `html`. A custom template is not plain HTML: it is a
            Mustache template that formcarry fills in for every submission. See
            the documentation on custom email templates for how it works.
        theme:
          type: string
          enum:
            - formal
            - fancy
          description: The built-in theme, used when type is formcarry.
        html:
          type: string
          nullable: true
          maxLength: 200000
          description: >-
            Your own template, used when type is custom. Not plain HTML: a
            Mustache template with tags such as {{email}} that formcarry fills
            in for every submission. See the documentation on custom email
            templates for the tags and the rules.
    SenderBlock:
      type: object
      properties:
        type:
          type: string
          enum:
            - formcarry
            - email_server
            - premium_server
          description: >-
            formcarry: sent from formcarry. email_server: one of your own SMTP
            servers. premium_server: one of your verified sending domains.
        server_id:
          type: string
          nullable: true
          maxLength: 64
          description: >-
            The id of the server, from GET /v1/email-servers. Required for
            email_server and premium_server, null for formcarry.
        name:
          type: string
          nullable: true
          maxLength: 128
          description: Sender name, premium_server only. Null for the other types.
        email:
          type: string
          nullable: true
          maxLength: 320
          description: >-
            Sender address, premium_server only. Must belong to the verified
            domain. Null for the other types.
    AutoResponseTemplateBlock:
      type: object
      properties:
        type:
          type: string
          enum:
            - formcarry
            - custom
          description: >-
            formcarry: one of the built-in themes with your message. custom:
            your own template, sent in `html`. A custom template is not plain
            HTML: it is a Mustache template that formcarry fills in for every
            submission. See the documentation on custom email templates for how
            it works.
        theme:
          type: string
          enum:
            - formal
            - fancy
          description: The built-in theme, used when type is formcarry.
        message:
          type: string
          nullable: true
          maxLength: 20000
          description: The message body, used when type is formcarry.
        html:
          type: string
          nullable: true
          maxLength: 200000
          description: >-
            Your own template, used when type is custom. Not plain HTML: a
            Mustache template with tags such as {{email}} that formcarry fills
            in for every submission. See the documentation on custom email
            templates for the tags and the rules.
    AfterSubmitPageBlock:
      type: object
      properties:
        theme:
          type: string
          enum:
            - sweet
            - fancy
            - formal
        mode:
          type: string
          enum:
            - light
            - dark
            - system
          description: Light or dark colours, or follow the visitor's system setting.
        headline:
          type: string
          nullable: true
          maxLength: 256
          description: The page title.
          example: Thank you!
        message:
          type: string
          nullable: true
          maxLength: 2000
          description: The text under the title.
          example: We have received your submission
        logo_url:
          type: string
          nullable: true
          maxLength: 2048
          description: Logo for the light look.
          example: https://example.com/thanks
        logo_dark_url:
          type: string
          nullable: true
          maxLength: 2048
          description: Logo for the dark look.
          example: https://example.com/thanks
        logo_size:
          type: string
          enum:
            - normal
            - big
        primary_color:
          type: string
          nullable: true
          maxLength: 32
          description: A CSS colour.
          example: '#0f766e'
        secondary_color:
          type: string
          nullable: true
          maxLength: 32
          description: A CSS colour.
          example: '#f0fdfa'
        return_button:
          description: The button that sends the visitor back to your site.
          allOf:
            - $ref: '#/components/schemas/PageButtonBlock'
        download_button:
          description: An optional second button, for example to a file.
          allOf:
            - $ref: '#/components/schemas/PageButtonBlock'
    AfterSubmitRedirectBlock:
      type: object
      properties:
        success_url:
          type: string
          nullable: true
          maxLength: 2048
          description: Where the visitor goes after a successful submission.
          example: https://example.com/thanks
        fail_url:
          type: string
          nullable: true
          maxLength: 2048
          description: >-
            Where the visitor goes when the submission is rejected. null uses
            success_url.
          example: https://example.com/thanks
        append_submission_to_url:
          type: boolean
          description: Append the submitted fields to the redirect URL as query parameters.
    ValidationRule:
      type: object
      properties:
        field:
          type: string
          maxLength: 128
          description: The name of the field in your HTML form.
          example: email
        checks:
          type: array
          items:
            $ref: '#/components/schemas/ValidationCheck'
      required:
        - field
        - checks
    WebhookSigning:
      type: object
      properties:
        algorithm:
          type: string
          example: hmac-sha256
        header:
          type: string
          example: X-Formcarry-Signature
      required:
        - algorithm
        - header
    WebhookLastDelivery:
      type: object
      properties:
        at:
          type: string
          example: '2026-09-13T12:00:00.000Z'
        status:
          type: string
          enum:
            - succeeded
            - failed
        response_status:
          type: number
          nullable: true
          example: 200
        attempt:
          type: number
          example: 1
      required:
        - at
        - status
        - response_status
        - attempt
    PageButtonBlock:
      type: object
      properties:
        text:
          type: string
          nullable: true
          maxLength: 64
          description: Button label. null hides the button.
        url:
          type: string
          nullable: true
          maxLength: 2048
          description: Where the button leads.
          example: https://example.com/thanks
    ValidationCheck:
      type: object
      properties:
        type:
          type: string
          enum:
            - required
            - email
            - url
            - phone_number
            - integer
            - min_length
            - max_length
            - contains
            - not_contains
        value:
          type: string
          nullable: true
          maxLength: 256
          description: The argument for min_length, max_length, contains and not_contains.
        message:
          type: string
          nullable: true
          maxLength: 512
          description: Replaces the default error message shown to the visitor.
      required:
        - type
  securitySchemes:
    api_key:
      scheme: bearer
      bearerFormat: fc_live_...
      type: http

````

## Related topics

- [Legacy Forms API — Create and Delete Forms](/docs/api/legacy/forms.md)
- [Quickstart](/docs/quickstart.md)
- [Introduction](/docs/introduction.md)
- [Legacy Formcarry API Overview](/docs/api/legacy/overview.md)
- [Connect over MCP](/docs/connect.md)
