Docs
Quickstart
- Sign in (email link or GitHub — no passwords) and create a form. You get an endpoint like
https://formreply.dev/f/ax3k9pz. - Paste it as your form's action:
<form action="https://formreply.dev/f/YOUR_FORM_ID" method="POST"> <input name="email" type="email" placeholder="you@site.com"> <textarea name="message"></textarea> <button type="submit">Send</button> </form>
Classic posts get a 302 redirect to your configured thank-you URL (set it in form settings, or pass a _next hidden field). Submissions show up in your inbox instantly.
AJAX / fetch
Send FormData or JSON with an Accept: application/json header and you'll get JSON back instead of a redirect:
const res = await fetch('https://formreply.dev/f/YOUR_FORM_ID', {
method: 'POST',
headers: { 'Accept': 'application/json' },
body: new FormData(form),
});
const { ok, id } = await res.json(); // { "ok": true, "id": "sub_…" }JSON body works too (Content-Type: application/json). CORS: lock your form to your domains with allowed domains in settings — entries like example.com, *.example.com, or *. Empty list = any origin.
Special fields (Formspree-compatible)
| Field | Effect |
|---|---|
_replyto | Submitter's email — used for reply-to on notifications and for the auto-reply. |
_subject | Overrides the notification email subject. |
_next | Redirect URL for classic posts (overrides the stored thank-you URL). |
_gotcha | Honeypot. Add it as a hidden input — bots fill it and are filed to spam silently (no notification sent). |
cf-turnstile-response | Cloudflare Turnstile token — verified when you configure a secret in spam settings. |
A plain email field is detected as the reply-to too. Everything else is stored verbatim in the submission.
Auto-reply
Enable auto-reply in form settings and every submission that includes an email gets an instant response. Subject and body support {field} placeholders filled from the submitted data — {name}, {email}, anything. Free sends from formreply.dev; Pro lets you use your own from-address.
Webhooks
Pro forms can register a generic webhook. On each submission we POST a signed JSON payload with up to 3 retries on failure:
POST https://your.endpoint/hook
X-FormReply-Signature: t=1698000000,v1=<hmac-sha256>
Content-Type: application/json
{
"event": "submission.created",
"form_id": "ax3k9pz",
"submission": {
"id": "sub_…",
"created_at": "2026-10-24 08:00:00",
"email": "visitor@site.com",
"data": { "name": "…", "message": "…" }
}
}Verify v1 as HMAC-SHA256 of `${t}.${rawBody}` with your webhook secret. Slack webhooks post a formatted message to your incoming-webhook URL.
Rate limits & spam
Per-IP (default 20/hour) and per-form (default 300/hour) limits return 429 when exceeded — tune them in spam settings. Spam (honeypot, disposable domain, failed Turnstile) is stored in the spam folder for 7 days, never silently deleted.
File uploads
Pro and Team plans accept multipart/form-data file inputs — 10 MB per file, 25 MB total per submission. Files are stored in R2 and downloadable only via short-lived signed links from the inbox.