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

# Forms

> Build public web forms that drop submissions straight into your CRM — with AI-assisted schema design and built-in spam protection.

<div
  style={{
background: "linear-gradient(135deg, #143D4E 0%, #1C758A 55%, #30C8CA 100%)",
borderRadius: "24px",
padding: "28px",
marginBottom: "28px",
color: "#FFFFFF",
boxShadow: "0 20px 50px rgba(20, 61, 78, 0.22)",
position: "relative",
overflow: "hidden",
border: "1px solid rgba(255,255,255,0.08)"
}}
>
  <div
    style={{
position: "absolute",
top: "-36px",
right: "-36px",
width: "170px",
height: "170px",
background: "rgba(255,255,255,0.08)",
borderRadius: "999px"
}}
  />

  <div
    style={{
position: "absolute",
bottom: "-48px",
left: "-24px",
width: "130px",
height: "130px",
background: "rgba(255,255,255,0.06)",
borderRadius: "999px"
}}
  />

  <div
    style={{
  display: "inline-flex",
  alignItems: "center",
  background: "rgba(255,255,255,0.14)",
  color: "#FFFFFF",
  padding: "7px 14px",
  borderRadius: "999px",
  fontSize: "12px",
  fontWeight: "700",
  marginBottom: "12px",
  letterSpacing: "0.08em",
  textTransform: "uppercase"
}}
  >
    FORMS
  </div>

  <p style={{ margin: 0, fontSize: "16px", lineHeight: "1.9", maxWidth: "760px", color: "#FFFFFF" }}>
    Spin up public web forms in minutes — describe the form you want in plain English and ParsaLink builds the schema, generates the page, and wires submissions to the right CRM entity.
  </p>
</div>

## Creating a Form

<Steps>
  <Step title="Open the Forms section">
    Go to **CRM → Forms → New Form**.
  </Step>

  <Step title="Describe it (optional)">
    Paste a description like *"A contact form for prospects with name, email, company, and a free-text message"* and click **Build with AI**. The schema builder drafts fields, types, and required flags for you. Or skip this and start from a blank form.
  </Step>

  <Step title="Refine fields">
    Add, remove, or rename fields. Each field has a type (text, long text, email, phone, number, select, multi-select), a required toggle, and an optional default value.
  </Step>

  <Step title="Pick the target entity">
    Choose what each submission creates: a **Contact**, **Lead** (contact with a specific stage), **Account**, or **Case**.
  </Step>

  <Step title="Set the Source and Tags">
    Stamp every submission with a Source value and any Tags so downstream [Automations](/automations/overview) can pick them up.
  </Step>

  <Step title="Publish">
    Save and click **Get Public Link**. The form is live at `https://app.parsalink.io/portal/{'{'}tenant-slug{'}'}/forms/{'{'}form-slug{'}'}`.
  </Step>
</Steps>

***

## Spam Protection

Every public form is protected with Cloudflare Turnstile (similar to reCAPTCHA but privacy-preserving). Genuine humans don't notice it; bots hit a friction wall.

If you want stricter validation on top, add:

* **Required email** field — combined with email format validation, this filters out drive-by submissions.
* **Hidden honeypot fields** — automatically inserted by ParsaLink; bots that fill them are silently dropped.
* **Rate limiting** by IP — enforced at the gateway.

***

## What Happens on Submission

1. The form payload hits `/api/crm/forms/public/{'{'}tenant_slug{'}'}/{'{'}form_slug{'}'}/submit/`.
2. Cloudflare Turnstile verifies the submission isn't a bot.
3. ParsaLink creates the configured entity (Contact / Account / Case / etc.) with the Source and Tags you set.
4. Any matching `contact_created` / `contact_source_changed` / `tag_added` automation rules fire.

The full submission JSON is also stored on the entity's `data` field, so even fields not mapped to a CRM column are preserved.

<Note>
  If the form creates a Contact and an `email` field is filled in, ParsaLink checks for duplicates by email. The default behavior is to update the existing contact rather than create a duplicate — useful for "request a demo" forms where the same person might submit twice.
</Note>

***

## Embedding the Form

You can:

* **Link** to the hosted page (`/portal/{'{'}tenant{'}'}/forms/{'{'}slug{'}'}`)
* **Embed** the hosted page in an iframe
* **Use the API directly** — POST a JSON payload to the submit endpoint (handy if you want full design control on your own site)

For API submissions, include the Turnstile token from your own Turnstile widget in the payload as `cf_turnstile_token`.

***

## Tracking Submissions

Every form has a submissions tab showing chronological entries, the source IP, and the created entity. Click any submission to open the contact/account/case it produced — useful for QA-ing a new form before you broadcast it.

<Tip>
  Pair a public form with a `contact_source_changed` automation rule (matching the source you stamped on the form) to instantly run a welcome sequence on every submission.
</Tip>
