# Contact form template you can host in one call

Short answer: a contact form doesn't need a form builder subscription — it
needs five fields and somewhere for the message to land. This is a complete
QuizGen JSON definition: name, email, what it's about, the message, and an
optional phone number. POST it and you get a hosted page at a short link;
wire a [webhook](/blog/quiz-response-webhooks) and messages hit Slack or
your inbox the moment someone submits, instead of sitting in a dashboard
you have to remember to check.

## The template

```json
{
  "schema_version": 1,
  "kind": "form",
  "title": "Contact us",
  "description": "We usually reply within one business day.",
  "sections": [
    {
      "key": "message",
      "questions": [
        { "id": "full_name", "type": "short_text", "prompt": "Your name",
          "required": true, "placeholder": "Jordan Smith" },
        { "id": "email", "type": "email", "prompt": "Your email",
          "required": true, "placeholder": "you@company.com" },
        { "id": "topic", "type": "choice", "prompt": "What's this about?",
          "required": true,
          "options": [
            { "value": "sales", "label": "Sales question" },
            { "value": "support", "label": "Support" },
            { "value": "other", "label": "Something else" }
          ] },
        { "id": "company_size", "type": "choice",
          "prompt": "Roughly how big is your team?",
          "show_if": { "question": "topic", "op": "eq", "value": "sales" },
          "options": [
            { "value": "solo", "label": "Just me" },
            { "value": "small", "label": "2-10" },
            { "value": "mid", "label": "11-50" },
            { "value": "large", "label": "50+" }
          ] },
        { "id": "phone", "type": "phone", "prompt": "Phone (optional)",
          "help": "Only if you'd rather we call." },
        { "id": "message", "type": "long_text", "prompt": "Your message",
          "required": true, "rows": 5 }
      ]
    }
  ],
  "settings": {
    "completion": { "message": "Thanks — we'll get back to you within a business day." }
  }
}
```

That's the whole form. Simplicity is the point: every field earns its
place, and there's nothing to trim.

## What each piece is doing

- `kind: "form"` — all six fields render on one page rather than one
  question per screen, which is what people expect from a contact form.
- `email` (not `short_text`) — QuizGen validates the format before the
  response is stored, so you don't get "reply" requests with no working
  address in them. A plain text field would accept "n/a" and call it done.
- `topic` as a `choice` — lets you route or triage without reading every
  message first, and it's what makes the `show_if` below possible.
- `company_size` only appears when `topic` is "sales", via `show_if`:
  one condition (`question`, `op`, `value`) referencing the earlier
  answer. Support requests never see a question that doesn't apply to them.
- `phone` is optional and last — most people won't fill it in, and that's
  fine; it's there for the minority who'd rather talk than type.

## Route it somewhere, don't just collect it

A contact form nobody checks is worse than no contact form. Set a
[webhook](/blog/quiz-response-webhooks) once (`POST /quizzes/:id/webhook`
with your endpoint URL) and every completed submission POSTs itself to you
immediately — forward it to Slack, create a ticket, or drop it into your
CRM. That's the actual reason to run a contact form as an API object instead
of a page a designer built once: the data has somewhere to go without you
polling a dashboard.

## Honest note on spam

QuizGen has no CAPTCHA today — say that plainly rather than pretend
otherwise. What does help: the required, structured fields above reject a
lot of junk on their own (a bare text box invites paste-and-submit bots;
an `email` field with real validation and a required `choice` don't), and
the submission endpoint isn't a public `<form action="...">` target that
scrapers find by crawling HTML — it's a JSON API a bot has to specifically
target. That's meaningfully less exposed than a bare HTML form, not
immune. If you start seeing spam, add a webhook and filter on it, or
switch `topic` values case by case.

## Build it with an AI assistant

Any assistant connected to [QuizGen's MCP server](/blog/claude-mcp-servers-for-quizzes-and-forms)
can adapt this without you touching JSON. For example:

> Read https://quizgen.dev/blog/contact-form-template.md and make me a
> contact form for my landscaping business — add a "preferred contact
> time" choice and drop the phone field. Give me the link.

It reshapes the template, POSTs it, and hands back the live URL.

## When a form plugin is the better pick

If the form just needs to sit embedded on a WordPress or Webflow page and
you'll never touch an API or route submissions programmatically, a native
form plugin (WPForms, Webflow's built-in forms) is genuinely simpler —
it's already wired into the page, no separate hosted link involved.
QuizGen's contact form wins once an assistant or your own code is the one
creating or updating it, or once you want submissions routed to Slack,
email, or a CRM the instant they arrive rather than read from a dashboard.

## FAQ

**Can I skip the topic field?** Yes, but you lose the routing and the
`show_if` follow-up — for a single-purpose form ("just email us") that's a
reasonable trade.

**Does the email field stop typos?** It checks the format (something@
something.tld), not that the address is real or reachable — that's true of
essentially every form on the web.

**Can I cap how many messages come in?** Add `"max_responses": 50` to
`settings` if you want the form to close itself after a batch, or
`"close_at"` for a date-based cutoff.

**Can I collect the message and take a payment?** Add a `payment` question
type (Business plan, after Stripe onboarding) — see the
[invoice template](/blog/invoice-template) for a worked example of that
pattern.
