---
title: "Create a form"
method: POST
path: "/v1/forms"
tags: ["forms"]
---

# Create a form

`POST /v1/forms`

## Request

- Base URL: `https://api.formcarry.com`
- URL: `https://api.formcarry.com/v1/forms`
- Auth: HTTP bearer

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.

## Request body

- CreateFormBody
  - `active` boolean: Inactive forms reject submissions.
  - `folder_id` string, nullable: The folder the form is filed in. null for no folder.
  - `storage` StorageBlock
    - `store_submissions` boolean: When false, submissions are forwarded by email and webhook but nothing is stored.
    - `keep_for` '30_days' | '60_days' | '90_days' | '180_days' | '365_days' | 'forever': How long stored submissions are kept before they are removed.
  - `spam` SpamBlock
    - `protection` boolean: formcarry's built-in spam filter.
    - `captcha` CaptchaBlock
      - `provider` 'none' | 'recaptcha' | 'hcaptcha' | 'turnstile': Which captcha your form embeds. formcarry verifies the response with this secret key.
      - `secret_key` string, nullable: 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.
      - `secret_key_set` boolean: Whether a secret key is stored. Read only: ignored on a write, so a form read and sent back whole is fine.
  - `self_email_notification` SelfEmailNotificationBlock
    - `enabled` boolean: Send an email to the recipients on every submission.
    - `recipients` string[]: Who receives the email. Replaces the whole list. The free plan allows one address.
    - `include_spam` boolean: Also send the email for submissions the spam filter flagged.
    - `subject` string, nullable: Email subject. null uses formcarry's default.
    - `logo_url` string, nullable: 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.
    - `logo_height` number, nullable: Logo height in pixels. null lets the template decide.
    - `template` SelfEmailNotificationTemplateBlock
      - `type` 'formcarry' | 'custom': 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` 'formal' | 'fancy': The built-in theme, used when type is formcarry.
      - `html` string, nullable: 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.
    - `sender` SenderBlock
      - `type` 'formcarry' | 'email_server' | 'premium_server': formcarry: sent from formcarry. email_server: one of your own SMTP servers. premium_server: one of your verified sending domains.
      - `server_id` string, nullable: The id of the server, from GET /v1/email-servers. Required for email_server and premium_server, null for formcarry.
      - `name` string, nullable: Sender name, premium_server only. Null for the other types.
      - `email` string, nullable: Sender address, premium_server only. Must belong to the verified domain. Null for the other types.
  - `auto_response` AutoResponseBlock
    - `enabled` boolean: Send a reply to the person who submitted the form (their email field is used as the address).
    - `subject` string, nullable: Subject of the reply.
    - `from_name` string, nullable: The name the reply appears to come from.
    - `logo_url` string, nullable: 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.
    - `logo_height` number, nullable: Logo height in pixels. null lets the template decide.
    - `template` AutoResponseTemplateBlock
      - `type` 'formcarry' | 'custom': 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` 'formal' | 'fancy': The built-in theme, used when type is formcarry.
      - `message` string, nullable: The message body, used when type is formcarry.
      - `html` string, nullable: 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.
  - `after_submit` AfterSubmitBlock
    - `type` 'formcarry_page' | 'redirect': formcarry_page: show formcarry's thank you page. redirect: send the visitor to your own URL.
    - `page` AfterSubmitPageBlock
      - `theme` 'sweet' | 'fancy' | 'formal'
      - `mode` 'light' | 'dark' | 'system': Light or dark colours, or follow the visitor's system setting.
      - `headline` string, nullable: The page title.
      - `message` string, nullable: The text under the title.
      - `logo_url` string, nullable: Logo for the light look.
      - `logo_dark_url` string, nullable: Logo for the dark look.
      - `logo_size` 'normal' | 'big'
      - `primary_color` string, nullable: A CSS colour.
      - `secondary_color` string, nullable: A CSS colour.
      - `return_button` PageButtonBlock
        - `text` string, nullable: Button label. null hides the button.
        - `url` string, nullable: Where the button leads.
      - `download_button` PageButtonBlock
        - `text` string, nullable: Button label. null hides the button.
        - `url` string, nullable: Where the button leads.
    - `redirect` AfterSubmitRedirectBlock
      - `success_url` string, nullable: Where the visitor goes after a successful submission.
      - `fail_url` string, nullable: Where the visitor goes when the submission is rejected. null uses success_url.
      - `append_submission_to_url` boolean: Append the submitted fields to the redirect URL as query parameters.
  - `validation` ValidationBlock
    - `enabled` boolean: Reject submissions that fail the rules.
    - `rules` ValidationRule[]: Replaces the whole list.
      - `field` string, required: The name of the field in your HTML form.
      - `checks` ValidationCheck[], required
        - `type` 'required' | 'email' | 'url' | 'phone_number' | 'integer' | 'min_length' | 'max_length' | 'contains' | 'not_contains', required
        - `value` string, nullable: The argument for min_length, max_length, contains and not_contains.
        - `message` string, nullable: Replaces the default error message shown to the visitor.
  - `team_id` string: Team that owns the new form. Required when the credential covers several teams (OAuth connections).
  - `name` string, required

## Response `201`

- FormResource
  - `id` string, required
  - `team_id` string, required
  - `name` string, required
  - `endpoint` string, required: Where your HTML form posts.
  - `active` boolean, required: Inactive forms reject submissions.
  - `avatar` string, required
  - `folder_id` string, nullable, required: The folder the form is filed in, or null for none.
  - `created_at` string, required
  - `last_submission_at` string, nullable, required: When the newest submission arrived, or null before the first.
  - `submissions` SubmissionCounts, required
    - `this_month` number, required: Submissions received this calendar month.
    - `all_time` number, nullable, required: Submissions received since the form was created.
  - `storage` StorageBlock, required
    - `store_submissions` boolean: When false, submissions are forwarded by email and webhook but nothing is stored.
    - `keep_for` '30_days' | '60_days' | '90_days' | '180_days' | '365_days' | 'forever': How long stored submissions are kept before they are removed.
  - `spam` SpamBlock, required
    - `protection` boolean: formcarry's built-in spam filter.
    - `captcha` CaptchaBlock
      - `provider` 'none' | 'recaptcha' | 'hcaptcha' | 'turnstile': Which captcha your form embeds. formcarry verifies the response with this secret key.
      - `secret_key` string, nullable: 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.
      - `secret_key_set` boolean: Whether a secret key is stored. Read only: ignored on a write, so a form read and sent back whole is fine.
  - `self_email_notification` SelfEmailNotificationBlock, required
    - `enabled` boolean: Send an email to the recipients on every submission.
    - `recipients` string[]: Who receives the email. Replaces the whole list. The free plan allows one address.
    - `include_spam` boolean: Also send the email for submissions the spam filter flagged.
    - `subject` string, nullable: Email subject. null uses formcarry's default.
    - `logo_url` string, nullable: 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.
    - `logo_height` number, nullable: Logo height in pixels. null lets the template decide.
    - `template` SelfEmailNotificationTemplateBlock
      - `type` 'formcarry' | 'custom': 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` 'formal' | 'fancy': The built-in theme, used when type is formcarry.
      - `html` string, nullable: 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.
    - `sender` SenderBlock
      - `type` 'formcarry' | 'email_server' | 'premium_server': formcarry: sent from formcarry. email_server: one of your own SMTP servers. premium_server: one of your verified sending domains.
      - `server_id` string, nullable: The id of the server, from GET /v1/email-servers. Required for email_server and premium_server, null for formcarry.
      - `name` string, nullable: Sender name, premium_server only. Null for the other types.
      - `email` string, nullable: Sender address, premium_server only. Must belong to the verified domain. Null for the other types.
  - `auto_response` AutoResponseBlock, required
    - `enabled` boolean: Send a reply to the person who submitted the form (their email field is used as the address).
    - `subject` string, nullable: Subject of the reply.
    - `from_name` string, nullable: The name the reply appears to come from.
    - `logo_url` string, nullable: 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.
    - `logo_height` number, nullable: Logo height in pixels. null lets the template decide.
    - `template` AutoResponseTemplateBlock
      - `type` 'formcarry' | 'custom': 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` 'formal' | 'fancy': The built-in theme, used when type is formcarry.
      - `message` string, nullable: The message body, used when type is formcarry.
      - `html` string, nullable: 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.
  - `after_submit` AfterSubmitBlock, required
    - `type` 'formcarry_page' | 'redirect': formcarry_page: show formcarry's thank you page. redirect: send the visitor to your own URL.
    - `page` AfterSubmitPageBlock
      - `theme` 'sweet' | 'fancy' | 'formal'
      - `mode` 'light' | 'dark' | 'system': Light or dark colours, or follow the visitor's system setting.
      - `headline` string, nullable: The page title.
      - `message` string, nullable: The text under the title.
      - `logo_url` string, nullable: Logo for the light look.
      - `logo_dark_url` string, nullable: Logo for the dark look.
      - `logo_size` 'normal' | 'big'
      - `primary_color` string, nullable: A CSS colour.
      - `secondary_color` string, nullable: A CSS colour.
      - `return_button` PageButtonBlock
        - `text` string, nullable: Button label. null hides the button.
        - `url` string, nullable: Where the button leads.
      - `download_button` PageButtonBlock
        - `text` string, nullable: Button label. null hides the button.
        - `url` string, nullable: Where the button leads.
    - `redirect` AfterSubmitRedirectBlock
      - `success_url` string, nullable: Where the visitor goes after a successful submission.
      - `fail_url` string, nullable: Where the visitor goes when the submission is rejected. null uses success_url.
      - `append_submission_to_url` boolean: Append the submitted fields to the redirect URL as query parameters.
  - `webhooks` WebhookResource[], required: Managed at /v1/forms/{form_id}/webhooks; one per form for now.
    - `id` string, required
    - `url` string, required
    - `enabled` boolean, required
    - `description` string, nullable, required
    - `events` string[], required
    - `signing` WebhookSigning, required
      - `algorithm` string, required
      - `header` string, required
    - `last_delivery` WebhookLastDelivery, required
      - `at` string, required
      - `status` 'succeeded' | 'failed', required
      - `response_status` number, nullable, required
      - `attempt` number, required
    - `created_at` string, required
  - `validation` ValidationBlock, required
    - `enabled` boolean: Reject submissions that fail the rules.
    - `rules` ValidationRule[]: Replaces the whole list.
      - `field` string, required: The name of the field in your HTML form.
      - `checks` ValidationCheck[], required
        - `type` 'required' | 'email' | 'url' | 'phone_number' | 'integer' | 'min_length' | 'max_length' | 'contains' | 'not_contains', required
        - `value` string, nullable: The argument for min_length, max_length, contains and not_contains.
        - `message` string, nullable: Replaces the default error message shown to the visitor.

## Other responses

- `400`: The body has a field that is missing, unknown or has the wrong value. `param` names it.
- `401`: The request carried no usable key or token.
- `403`: The key is valid but may not create this form.
- `429`: Slow down and retry after the Retry-After header.

---

[API](https://skmtc.dev/formcarry/apis/formcarry-api.md) · [All operations](https://skmtc.dev/formcarry/apis/formcarry-api/llms.txt) · [OpenAPI document](https://skmtc.dev/formcarry/apis/formcarry-api/revisions/c971f37d5987?raw)
