quickforms
Get started

Hosted form backend

Point any form at one URL. We handle the rest.

Share a hosted form, send personal links, or post from your own markup. quickforms validates every submission, filters spam, stores it, emails you and posts it to your webhook with a signature and retries. Test it all in sandbox mode, and drive it from the dashboard, the REST API or MCP.

  • Hosted forms
  • Personal links
  • AI spam filter
  • Signed webhooks
  • REST API and MCP
POST /f/01jc8xk2
Contact us<form action="/f/01jc8xk2" method="post">NameEmailMessageSendquickforms✓ validated · storedNotificationpendingto: you@yourdomain.comNew submission: ContactWebhookpendingQuickforms-Event: submission.createdQuickforms-Signature:t=1762430400,v1=9f86d081884c7d65…#15002140msretry in 10s#2200142msdeliveredbackoff 10s · 1m · 5m · 30m · 2h · 6hAutoresponderpendingto: ada@example.comThanks, we got your messagewebhook body · application/json

How it works

Three steps from markup to inbox

No server to write for every site. Keep your own HTML, your own design and your own email provider.

  1. 01

    Build your form

    Describe it to the AI form builder, start from a template or write the schema yourself. Save changes as a draft and publish when they are ready.

    { "name": "email", "type": "email", "required": true }
  2. 02

    Share it or point at it

    Share the hosted form page, send personal links, set your own form action to the endpoint, post JSON from your app, or drop in the embed script.

    <form action="/f/FORM_ID" method="post">
  3. 03

    Get it everywhere

    Every submission is validated, checked for spam, stored, emailed to you and posted to your webhook with a signature. Failed deliveries retry on a backoff schedule.

    Quickforms-Event: submission.created

Hosted forms

No website needed. Share the link.

Every form has its own page at /f/FORM_ID, styled the way you choose. Open it in a browser and it is a form. Post to the same URL and it is an endpoint.

  • Classic, compact, or steps: one question at a time, with keyboard shortcuts and a review before sending
  • Light, dark or automatic, with your accent colour, font, corners, background, intro and logo
  • File uploads, honeypots and Turnstile work on it out of the box
  • Preview a draft with ?sandbox= before you publish it
/f/FORM_ID?link=lnk_7Hq2…
1 of 3

1→What's your name?

Ada Lovelace

Prefilled from your link

Next

"hosted": { "layout": "steps", "accent": "#7c3aed", "background": "grid" }

Build and validate

Describe it, pick a template, or write the schema

The AI form builder turns a plain-English description into fields, smart rules, a success message and an autoresponder for you to review. Or start from a template. Either way, every field becomes a validation rule, so bad input never reaches your inbox or your webhook.

  • text, textarea, email, url, tel, number, date, select, radio, checkbox, checkboxes, hidden and file
  • required, min and max for length, value, count or date, pattern, options, accept and max_size_kb
  • Custom error messages per field, shown inline on the hosted page and in the embed
  • Save changes as a draft, test them in sandbox mode, then publish or discard
schema.fields
{ "name": "email", "type": "email", "required": true }
required|string|email:rfc|max:254
{ "name": "plan", "type": "select", "options": ["starter", "pro"] }
nullable|string|in:starter,pro
{ "name": "seats", "type": "number", "integer": true, "min": 1, "max": 50 }
nullable|integer|min:1|max:50
POST /f/01jc8xk2application/json
{
"email": "ada@",email
"plan": "enterprise",in
"seats": 0min
}
response422 Unprocessable Content

Examples

Start from a form that already works

Real templates, ready to go: fields, validation, an autoresponder and smart rules for the spam filter. Pick one, change anything, then share the hosted link or point your own form at it.

Contact

Name, email and a message, with a confirmation email to the person who wrote in.

  • 3 fields: Name, Email, Message
  • Autoresponder: Thanks {{name}}, we got your message
Use this template

Everything is editable after you pick it.

quickforms.test/f/…

Contact

Name*
Email*
Message*
Submit

Features

Everything a form endpoint should do

The boring, important parts, done properly once so you do not have to do them again for every site.

Hosted forms

A themed page for every form in a classic, steps or compact layout, with light and dark modes, your accent, font and logo.

Personal links

One link per person with prefilled answers, your own metadata, a use limit and an expiry. Used links say so.

AI form builder

Describe the form in plain English and get fields, smart rules, a success message and an autoresponder to review.

Templates

Ready-made starting points for contact, quotes, newsletters, waitlists, feedback, RSVPs, job applications and more.

Drafts and publishing

Save changes as a draft and test them in sandbox mode while live submissions keep the published version.

Schema validation

Thirteen field types. Every field becomes a server-side rule, with 422 errors keyed by field.

AI spam filter

Every submission is classified before anything is sent. Spam is kept for review and its deliveries are held.

Smart rules

Plain-English rules per form, such as "Must be about bike fitting". Submissions that break them are held too.

Bot protection

Up to six honeypots with realistic names, and Cloudflare Turnstile with your own site key and secret key.

Double opt-in

Send a confirmation email first and hold every other email and webhook until the person confirms.

Direct uploads

Pre-signed URLs send files straight to storage, or post them as multipart. Type and size rules per field.

Sandbox mode

Validate and store test submissions without sending anything, and see exactly what would have gone out.

Signed webhooks

HMAC SHA-256 signatures with a timestamp, retries with backoff and a log of every attempt.

Email, your keys

Notify your team and reply to the sender through your own email provider, or the platform mailer.

HTML, JSON and embed

HTML posts get a redirect or a thank-you page, JSON clients get JSON, and one script tag renders the form.

CORS and rate limits

Allowed origins per form, safe redirects, and submissions limited per form and IP address.

See every feature

Drop-in

Plain HTML, an embed, or one request

Use the markup you already have. Add the embed script to render the form for you. Or post JSON from any backend, script or serverless function.

  • _redirect sends people back to your site, or use the hosted thank-you page
  • The embed renders every field type, posts with fetch and fires quickforms:success and quickforms:error events
  • Prefer an iframe? Every form has a hosted embed page too
index.html
<form action="https://quickforms.test/f/FORM_ID" method="post">
  <input name="name" required>
  <input name="email" type="email" required>
  <textarea name="message"></textarea>

  <!-- Honeypot: hidden from people, bots fill it in -->
  <input name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">

  <!-- Optional: send people here afterwards (the host must be trusted by the form) -->
  <input type="hidden" name="_redirect" value="https://yoursite.com/thanks">

  <button type="submit">Send</button>
</form>
X-Quickforms-Sandbox: qf_sandbox_9vX2…
notificationpending
to
you@yourdomain.com
subject
[Sandbox] New submission: Contact
provider
Postmark (Main)

Would have sent. Nothing left the app.

webhookpending
POST https://example.com/hooks
Quickforms-Event: submission.created
Quickforms-Signature:
t=1762430400,v1=4b1e0c7d9a…
{ "sandbox": false, … }

Signed exactly as the receiver would have seen it.

201 responseapplication/json
{ "id": "01jca9qf3t…", "sandbox": false, "deliveries": null }

Sandbox mode

Test for real. Send nothing.

Sandbox submissions are validated and stored like any other, but no email or webhook leaves the app. Instead you see what would have been sent, down to the webhook signature header.

  • Send the form sandbox key as X-Quickforms-Sandbox or a _sandbox field
  • Switch a whole form to sandbox mode while you build it
  • Sandbox submissions run against your draft, so you can test changes before you publish
  • Preview the hosted page with ?sandbox=, and see the spam verdict on every test
  • Set QUICKFORMS_FORCE_SANDBOX=true for a whole environment
  • Test submissions from the dashboard, API and MCP are always sandbox

Spam and bots

Four layers between bots and your inbox

Each layer catches what the one before it missed. Anything the spam filter flags is stored for review, and its emails and webhooks are held until you release it.

  1. 01

    Rate limiting

    Submissions are limited per form and IP address, with a clear 429 for anyone sending too many.

    QUICKFORMS_RATE_LIMIT=30
  2. 02

    Honeypots

    A hidden main honeypot plus up to five extra ones with realistic names. Bots that fill them in get a normal success and are dropped.

    "honeypot_fields": ["website", "fax"]
  3. 03

    Cloudflare Turnstile

    Require a Turnstile token on live submissions, checked server-side with your own site key and secret key.

    cf-turnstile-response
  4. 04

    AI spam filter

    Every submission is classified before anything is sent, against a base spam check and your own plain-English smart rules.

    "rules": ["Must be about bike fitting"]

Webhooks

Signed, retried and logged

Every webhook carries a timestamped HMAC SHA-256 signature, so you can prove it came from quickforms and reject replays. If your endpoint is down, quickforms retries on a backoff schedule and logs every attempt.

  • Quickforms-Signature: t=<unix>,v1=<hex>
  • Retries after 10s, 1m, 5m, 30m, 2h and 6h
  • Status code, response excerpt, duration and next retry for each attempt
  • Redeliver from the dashboard, the API or MCP
  • Includes the personal link and your metadata when the submission came through one
  • Held for spam until you release it, and for double opt-in until the person confirms
  • URLs that resolve to private or reserved addresses are refused
verify.js
import crypto from "node:crypto";

// Use the raw request body, exactly as received, not a re-serialised object.
export function verifyQuickforms(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    header.split(",").map((part) => part.trim().split("=", 2)),
  );
  const timestamp = Number(parts.t);
  const signature = parts.v1 ?? "";

  if (!timestamp || !signature) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  return expected.length === signature.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
delivery · webhook · https://example.com/hookspending
attemptstatusdurationresponse / next retry
#15031840msnext retry in 10s
#2err10000msconnection timed out · next retry in 1m
#320096ms{"received":true}
backoff schedule7 attempts max
10s
1m
5m
30m
2h
6h
Every attempt is logged. Redeliver any live delivery by hand.Redeliver

Bring your own keys

Email through the provider you already use

Add your own provider credentials per team, set a default, or pick one per form. Credentials are encrypted at rest and only ever shown masked. No provider set? The platform mailer sends it.

ResendPostmarkMailgunAmazon SESSMTPMailchimp Transactional (Mandrill)Platform default mailer

Notification email

Every field, to the addresses you choose or the team owner. Reply-to is the sender.

Autoresponder

Optional reply to the person who submitted, with {{name}} style placeholders.

API and MCP

Same powers in the dashboard, the API and your agent

Forms, templates, the AI form builder, drafts, personal links, submissions, spam review, deliveries and mail providers are all available over a REST API with team-scoped API keys. The same key connects an MCP client, so an agent can design a form, send a test submission, hand out personal links and read what would have been delivered.

list-formsget-formlist-form-templatesgenerate-formcreate-formupdate-formpublish-formcreate-form-linkslist-form-linkssend-test-submissionlist-submissionsget-submissionreview-submissionconfirm-submissionredeliverlist-partial-submissionsmanage-destinationget-form-analytics

Create API keys on the API keys page of your team.

send a sandbox test submission
curl -X POST https://quickforms.test/api/v1/forms/FORM_ID/test-submissions \
  -H "Authorization: Bearer $QUICKFORMS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"data": {"name": "Ada Lovelace", "email": "ada@example.com"}}'

Your next form needs a backend. This is it.

Describe a form, share its hosted page or copy the endpoint, and send your first sandbox submission.